C语言多线程编程入门:从基础到高级实战
C语言多线程编程入门:从基础到高级实战
本文将详细介绍如何在C语言中使用POSIX线程库(pthread)创建和管理线程。从基础的线程创建到高级的线程池实现,通过代码示例和详细解释,帮助读者全面理解C语言多线程编程。
一、包含pthread.h头文件
要在C语言中使用POSIX线程库,首先需要包含pthread.h头文件。该头文件提供了创建和管理线程所需的所有函数和数据类型。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
二、调用pthread_create函数
pthread_create函数用于创建新线程。其函数原型如下:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
其中,参数解释如下:
pthread_t *thread
:指向线程标识符的指针。const pthread_attr_t *attr
:指向线程属性对象的指针,通常设为NULL使用默认属性。void *(*start_routine)(void *)
:指向线程函数的指针,该函数将在新线程中执行。void *arg
:传递给线程函数的参数。
三、传递线程函数和参数
线程函数是新线程将要执行的代码。该函数必须符合特定的函数签名,即返回类型为void *
,参数为void *
。可以通过arg参数将任意类型的数据传递给线程函数。
四、示例代码
下面是一个简单的示例代码,演示如何在C语言中创建线程并传递参数。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
// 线程函数
void *thread_function(void *arg) {
int *num = (int *)arg;
printf("线程中的数字: %d\n", *num);
return NULL;
}
int main() {
pthread_t thread;
int num = 42;
// 创建线程
if (pthread_create(&thread, NULL, thread_function, &num) != 0) {
fprintf(stderr, "线程创建失败\n");
return 1;
}
// 等待线程结束
if (pthread_join(thread, NULL) != 0) {
fprintf(stderr, "线程等待失败\n");
return 2;
}
printf("主线程结束\n");
return 0;
}
五、线程同步
在多线程编程中,线程同步是一个重要的概念。它确保多个线程在访问共享资源时不会产生竞争条件。POSIX线程库提供了一些同步机制,如互斥锁(mutex)和条件变量。
六、互斥锁
互斥锁用于保护共享资源,确保在同一时间只有一个线程访问该资源。使用互斥锁时,线程在访问共享资源前必须先锁定互斥锁,访问完成后解锁互斥锁。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t mutex;
int shared_data = 0;
void *thread_function(void *arg) {
pthread_mutex_lock(&mutex);
shared_data++;
printf("线程更新后的共享数据: %d\n", shared_data);
pthread_mutex_unlock(&mutex);
return NULL;
}
int main() {
pthread_t thread1, thread2;
// 初始化互斥锁
if (pthread_mutex_init(&mutex, NULL) != 0) {
fprintf(stderr, "互斥锁初始化失败\n");
return 1;
}
// 创建线程
if (pthread_create(&thread1, NULL, thread_function, NULL) != 0) {
fprintf(stderr, "线程1创建失败\n");
return 2;
}
if (pthread_create(&thread2, NULL, thread_function, NULL) != 0) {
fprintf(stderr, "线程2创建失败\n");
return 3;
}
// 等待线程结束
if (pthread_join(thread1, NULL) != 0) {
fprintf(stderr, "线程1等待失败\n");
return 4;
}
if (pthread_join(thread2, NULL) != 0) {
fprintf(stderr, "线程2等待失败\n");
return 5;
}
// 销毁互斥锁
pthread_mutex_destroy(&mutex);
printf("主线程结束\n");
return 0;
}
七、条件变量
条件变量用于线程间的通信,允许一个线程等待另一个线程发出信号。条件变量通常与互斥锁一起使用,以确保对共享资源的访问是受保护的。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
int ready = 0;
void *thread_function(void *arg) {
pthread_mutex_lock(&mutex);
while (!ready) {
pthread_cond_wait(&cond, &mutex);
}
printf("线程收到信号\n");
pthread_mutex_unlock(&mutex);
return NULL;
}
int main() {
pthread_t thread;
// 初始化互斥锁和条件变量
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
// 创建线程
if (pthread_create(&thread, NULL, thread_function, NULL) != 0) {
fprintf(stderr, "线程创建失败\n");
return 1;
}
// 主线程发送信号
pthread_mutex_lock(&mutex);
ready = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
// 等待线程结束
if (pthread_join(thread, NULL) != 0) {
fprintf(stderr, "线程等待失败\n");
return 2;
}
// 销毁互斥锁和条件变量
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
printf("主线程结束\n");
return 0;
}
八、线程池
线程池是一组预先创建的线程,可以提高程序性能,特别是在需要频繁创建和销毁线程的情况下。通过重用现有线程,线程池减少了创建和销毁线程的开销。
九、创建线程池
要实现线程池,需要定义一个线程池结构体,包含线程数组、任务队列和同步机制。然后,创建线程并将它们放入池中,线程将从任务队列中提取任务并执行。
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define THREAD_POOL_SIZE 4
#define QUEUE_SIZE 10
typedef struct {
void (*function)(void *);
void *argument;
} Task;
typedef struct {
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_t threads[THREAD_POOL_SIZE];
Task task_queue[QUEUE_SIZE];
int task_count;
int head;
int tail;
int stop;
} ThreadPool;
void *worker_thread(void *arg) {
ThreadPool *pool = (ThreadPool *)arg;
while (1) {
pthread_mutex_lock(&pool->mutex);
while (pool->task_count == 0 && !pool->stop) {
pthread_cond_wait(&pool->cond, &pool->mutex);
}
if (pool->stop) {
pthread_mutex_unlock(&pool->mutex);
break;
}
Task task = pool->task_queue[pool->head];
pool->head = (pool->head + 1) % QUEUE_SIZE;
pool->task_count--;
pthread_mutex_unlock(&pool->mutex);
task.function(task.argument);
}
return NULL;
}
void thread_pool_init(ThreadPool *pool) {
pthread_mutex_init(&pool->mutex, NULL);
pthread_cond_init(&pool->cond, NULL);
pool->task_count = 0;
pool->head = 0;
pool->tail = 0;
pool->stop = 0;
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
pthread_create(&pool->threads[i], NULL, worker_thread, pool);
}
}
void thread_pool_destroy(ThreadPool *pool) {
pthread_mutex_lock(&pool->mutex);
pool->stop = 1;
pthread_cond_broadcast(&pool->cond);
pthread_mutex_unlock(&pool->mutex);
for (int i = 0; i < THREAD_POOL_SIZE; i++) {
pthread_join(pool->threads[i], NULL);
}
pthread_mutex_destroy(&pool->mutex);
pthread_cond_destroy(&pool->cond);
}
void thread_pool_add_task(ThreadPool *pool, void (*function)(void *), void *argument) {
pthread_mutex_lock(&pool->mutex);
pool->task_queue[pool->tail].function = function;
pool->task_queue[pool->tail].argument = argument;
pool->tail = (pool->tail + 1) % QUEUE_SIZE;
pool->task_count++;
pthread_cond_signal(&pool->cond);
pthread_mutex_unlock(&pool->mutex);
}
void sample_task(void *arg) {
int *num = (int *)arg;
printf("线程池任务: %d\n", *num);
sleep(1); // 模拟任务处理时间
}
int main() {
ThreadPool pool;
thread_pool_init(&pool);
for (int i = 0; i < 20; i++) {
int *num = malloc(sizeof(int));
*num = i;
thread_pool_add_task(&pool, sample_task, num);
}
sleep(10); // 等待所有任务完成
thread_pool_destroy(&pool);
printf("主线程结束\n");
return 0;
}
十、总结
在C语言中使用POSIX线程库(pthread)可以方便地创建和管理线程,从而实现并发编程。通过使用互斥锁、条件变量等同步机制,可以有效地避免竞争条件,确保线程安全。同时,通过实现线程池,可以提高程序性能,特别是在需要频繁创建和销毁线程的情况下。