学习Linux线程:深入理解,轻松上手,详解实例 (linux线程 例子)

随着计算机技术的不断发展,Linux作为一种开源的操作系统,得到了众多开发者和计算机爱好者的青睐。在Linux系统中,线程作为一种重要的机制,在许多应用程序中得到广泛的应用。

学习Linux线程,相信是每一位程序员成长过程中的必经之路。本文将从深入理解线程的概念、轻松上手线程的使用以及详解实例等方面,为大家呈现一份全面的Linux线程学习笔记。

一、深入理解线程的概念

线程是一个轻量级的进程,它是程序中执行的最小单元,是处理器调度和分派的基本单位。而进程是资源分配和调度的基本单位。一个进程包括一个或多个线程,这些线程共享进程资源,但每个线程又拥有自己独立的栈空间、程序计数器和线程上下文等。

在Linux系统中,每个线程都有一个线程ID(TID)和一个可能独立的堆栈,但是它们共享其它的资源,如进程ID、代码段、数据段、打开的文件和信号处理函数等。

线程的优点在于它可以减少进程之间的上下文切换开销,同时它也可以有效利用系统资源。但是线程也存在一些缺点,如同步、互斥的问题。因此,程序员需要根据具体情况选择进程和线程。

二、轻松上手线程的使用

为了更好地理解线程的使用,我们需要了解一些Linux系统提供的线程API。下面将介绍一些常用的线程API和其基本用法:

1. pthread_create()

pthread_create()函数是Linux系统中创建线程的最基本函数之一。该函数的原型如下所示:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,

void *(*start_routine) (void *), void *arg);

其中,pthread_t类型是一个线程ID。pthread_attr_t类型是用来指定线程属性的参数,如果这个参数为NULL,则线程将使用默认属性。

start_routine是一个指向函数的指针,该函数是线程的入口点。arg是传入start_routine函数的参数。

下面是一个使用pthread_create()函数创建线程的实例代码:

#include

#include

void *task(void *arg)

{

printf(“Thread is running …\n”);

return NULL;

}

int mn()

{

pthread_t tid;

pthread_create(&tid, NULL, task, NULL);

printf(“Thead has been created.\n”);

pthread_join(tid, NULL);

printf(“Thead has been finished.\n”);

return 0;

}

在这个例子中,我们使用pthread_create()函数创建了一个名为“task”的线程,并在该线程中输出了一个字符串。在主线程中,我们使用pthread_join()函数来等待“task”线程的结束。

2. pthread_mutex_t

pthread_mutex_t类型是Linux系统中用于线程同步的一种互斥锁,它是多线程编程中非常重要的一个概念。下面是这个类型的定义:

typedef struct {

volatile int __lock;

} pthread_mutex_t;

其中,__lock变量是用来表示锁的状态的,它的值为0时表示锁是未锁定状态,值为1时表示锁已锁定状态。

以下是一个使用pthread_mutex_t实现线程同步的示例:

#include

#include

pthread_mutex_t lock;

int count = 0;

void *task(void *arg)

{

pthread_mutex_lock(&lock);

printf(“Thread is running, count = %d\n”, count);

count++;

pthread_mutex_unlock(&lock);

return NULL;

}

int mn()

{

int i;

pthread_t tids[10];

pthread_mutex_init(&lock, NULL);

for (i = 0; i

pthread_create(&tids[i], NULL, task, NULL);

}

for (i = 0; i

pthread_join(tids[i], NULL);

}

pthread_mutex_destroy(&lock);

return 0;

}

在这个例子中,我们使用pthread_mutex_t来保证多个线程能够正确地对count变量进行操作。当一个线程使用pthread_mutex_lock()函数来锁定锁时,如果锁已经被其它线程锁定了,则当前线程会被阻塞,直到其它线程释放了锁。当当前线程执行完操作时,使用pthread_mutex_unlock()函数来释放锁。

三、详解实例

下面将通过一个实际应用,深入地了解Linux线程的使用方法。我们将使用线程来构建一个多线程FTP服务器,供客户端上传和下载文件。

1. 服务器端

服务器端的主要工作是使用socket接口来监听客户端的请求,在客户端的请求到来时,创建一个新的线程来处理客户端的请求。

下面是服务器端的实例代码:

#include

#include

#include

#include

#include

#include

#include

#include

#define PORT 8888

#define MAX_LINE 2023

void *client_handler(void *);

int mn()

{

int sock_fd, client_fd;

struct sockaddr_in server_addr, client_addr;

socklen_t client_len;

pthread_t tid;

sock_fd = socket(AF_INET, SOCK_STREAM, 0);

if (sock_fd == -1) {

perror(“socket”);

exit(-1);

}

memset(&server_addr, 0, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(PORT);

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {

perror(“bind”);

exit(-1);

}

if (listen(sock_fd, 5) == -1) {

perror(“listen”);

exit(-1);

}

client_len = sizeof(client_addr);

while (1) {

client_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &client_len);

if (client_fd == -1) {

perror(“accept”);

break;

}

if (pthread_create(&tid, NULL, client_handler, (void *)client_fd) != 0) {

perror(“pthread_create”);

break;

}

}

close(sock_fd);

return 0;

}

在这个例子中,我们使用socket接口来创建一个TCP套接字,然后绑定到指定的端口上,并使用listen()函数来进行监听。在接受客户端的连接请求时,我们创建了一个新的线程来处理客户端请求,这个线程的入口点是client_handler()函数。

2. 客户端

客户端主要的工作是向服务器发送上传和下载请求,并接收服务器返回的数据。

以下是客户端的实例代码:

#include

#include

#include

#include

#include

#include

#include

#define PORT 8888

#define MAX_LINE 2023

char server_ip[] = “127.0.0.1”;

void download_file(int sockfd, char *filename)

{

char buffer[MAX_LINE];

FILE *fp;

int len;

sprintf(buffer, “get %s”, filename);

if (send(sockfd, buffer, strlen(buffer), 0) == -1) {

perror(“send”);

exit(-1);

}

fp = fopen(filename, “wb”);

if (!fp) {

perror(“fopen”);

exit(-1);

}

while ((len = recv(sockfd, buffer, MAX_LINE, 0)) > 0) {

fwrite(buffer, 1, len, fp);

}

fclose(fp);

}

void upload_file(int sockfd, char *filename)

{

char buffer[MAX_LINE];

FILE *fp;

int len;

sprintf(buffer, “put %s”, filename);

if (send(sockfd, buffer, strlen(buffer), 0) == -1) {

perror(“send”);

exit(-1);

}

fp = fopen(filename, “rb”);

if (!fp) {

perror(“fopen”);

exit(-1);

}

while ((len = fread(buffer, 1, MAX_LINE, fp)) > 0) {

if (send(sockfd, buffer, len, 0) == -1) {

perror(“send”);

exit(-1);

}

}

fclose(fp);

}

int mn()

{

int sockfd;

struct sockaddr_in server_addr;

sockfd = socket(AF_INET, SOCK_STREAM, 0);

if (sockfd == -1) {

perror(“socket”);

exit(-1);

}

memset(&server_addr, 0, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_port = htons(PORT);

server_addr.sin_addr.s_addr = inet_addr(server_ip);

if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {

perror(“connect”);

exit(-1);

}

upload_file(sockfd, “test.txt”);

download_file(sockfd, “test.txt”);

close(sockfd);

return 0;

}

在这个例子中,我们使用socket接口来创建一个TCP套接字,并使用connect()函数来连接服务器。在向服务器发送上传请求和下载请求时,我们使用send()函数发送数据,接收数据时使用recv()函数。


数据运维技术 » 学习Linux线程:深入理解,轻松上手,详解实例 (linux线程 例子)