您的位置:

Linux 多线程详解

一、线程的概念

线程是操作系统调度的最小单位,它是进程中的一个执行单位。一个进程可以拥有多个线程,这些线程可以共享进程的资源,包括内存、文件等。线程之间的切换比进程之间的切换代价要小很多,也更加高效。在Linux系统中,线程的实现依赖于操作系统提供的POSIX线程库(pthread)。

二、线程的创建和销毁

线程的创建和销毁是多线程编程的基本操作。在Linux系统中,线程的创建和销毁都是通过pthread库提供的函数实现的。例如,创建一个线程可以使用pthread_create函数,销毁一个线程可以使用pthread_cancel函数。

void *thread_func(void *arg){
    printf("This is a pthread.\n");
    pthread_exit(NULL);
}
int main(){
    pthread_t tid;
    int ret = pthread_create(&tid, NULL, thread_func, NULL);  //创建一个线程
    if(ret){
        printf("Create pthread error!\n");
        return -1;
    }
    pthread_join(tid, NULL);  //等待子线程结束
    return 0;
}

在上面的示例代码中,pthread_t类型的tid变量储存着新建线程的线程ID。pthread_create函数接受四个参数,第一个参数是指向新线程标识符的指针,第二个参数用于设置线程属性,第三个参数是新线程运行的函数,第四个参数是传给函数的参数。pthread_join函数用于等待子线程结束。

三、线程同步与互斥

线程同步与互斥是多线程编程中必须掌握的概念,它们是保证多个线程安全共享数据的重要手段。Linux系统提供了多种同步和互斥机制,其中最常用的是互斥锁和条件变量。

pthread_mutex_t mutex;
pthread_cond_t cond;
void *thread_func(void *arg){
    // 模拟线程同步
    pthread_mutex_lock(&mutex);  // 加锁
    pthread_cond_wait(&cond, &mutex);  // 等待条件变量的信号
    pthread_mutex_unlock(&mutex);  // 解锁
    printf("Thread is over.\n");
    pthread_exit(NULL);
}
int main(){
    pthread_t tid;
    pthread_mutex_init(&mutex, NULL);  // 初始化互斥锁
    pthread_cond_init(&cond, NULL);  // 初始化条件变量
    int ret = pthread_create(&tid, NULL, thread_func, NULL);  // 创建一个线程
    if(ret){
        printf("Create pthread error!\n");
        return -1;
    }
    // 模拟线程同步
    sleep(5);
    pthread_cond_signal(&cond); // 发送信号
    pthread_join(tid, NULL); // 等待子线程结束
    pthread_mutex_destroy(&mutex);  // 销毁互斥锁
    pthread_cond_destroy(&cond);  // 销毁条件变量
    return 0;
}

在上面的示例代码中,使用pthread_mutex_t定义了互斥锁和pthread_cond_t定义了条件变量。pthread_mutex_lock和pthread_mutex_unlock函数用于加锁和解锁互斥锁,pthread_cond_wait函数用于等待条件变量的信号,pthread_cond_signal函数用于发送信号。

四、线程池

线程池是提高多线程执行效率的重要手段,它可以使得多个线程共享一定数量的线程资源,避免了线程频繁创建和销毁的开销。在Linux系统中,线程池的实现主要依赖于pthread库提供的线程创建、销毁和管理函数。

#define THREAD_NUM 5
#define QUEUE_SIZE 10
pthread_t threads[THREAD_NUM];
int queue[QUEUE_SIZE];
int front = 0, rear = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;
void *worker_func(void *arg){
    int thread_id = *(int *)arg;
    while(1){
        pthread_mutex_lock(&mutex);  // 加锁
        while(front == rear){  // 队列为空,等待信号
            pthread_cond_wait(&cond, &mutex);
        }
        int task = queue[front++];  // 从队列中取出任务
        printf("Thread %d get task %d.\n", thread_id, task);
        pthread_mutex_unlock(&mutex);  // 解锁
        sleep(2);  // 模拟任务执行
    }
    pthread_exit(NULL);
}
int main(){
    pthread_mutex_init(&mutex, NULL);
    pthread_cond_init(&cond, NULL);
    int tids[THREAD_NUM];
    for(int i = 0; i < THREAD_NUM; i++){
        tids[i] = i + 1;
        pthread_create(&threads[i], NULL, worker_func, &tids[i]);  // 创建线程
    }
    srand(time(NULL));
    for(int i = 0; i < 20; i++){  // 向队列中添加任务
        pthread_mutex_lock(&mutex);  // 加锁
        while((rear + 1) % QUEUE_SIZE == front){  // 队列已满,等待信号
            pthread_cond_wait(&cond, &mutex);
        }
        queue[rear] = rand() % 100;  // 添加任务
        rear = (rear + 1) % QUEUE_SIZE;
        printf("Task %d added to queue.\n", i);
        pthread_mutex_unlock(&mutex);  // 解锁
        pthread_cond_signal(&cond);  // 发送信号
        sleep(1);
    }
    for(int i = 0; i < THREAD_NUM; i++){
        pthread_cancel(threads[i]);  // 结束线程
    }
    pthread_mutex_destroy(&mutex);  // 销毁互斥锁
    pthread_cond_destroy(&cond);  // 销毁条件变量
    return 0;
}

在上面的示例代码中,创建了一个固定大小的队列来储存任务,使用互斥锁保证队列的线程安全,使用条件变量通信。线程池中包括多个工作线程,它们都从队列中获取任务进行执行。主线程向队列中添加任务,使用pthread_cond_broadcast函数给所有线程发送信号,线程池的核心在于阻塞等待队列消息,并动态创建线程。