一、线程的概念
线程是操作系统调度的最小单位,它是进程中的一个执行单位。一个进程可以拥有多个线程,这些线程可以共享进程的资源,包括内存、文件等。线程之间的切换比进程之间的切换代价要小很多,也更加高效。在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函数给所有线程发送信号,线程池的核心在于阻塞等待队列消息,并动态创建线程。