在C语言中,采用多线程编程,我们经常会遇到,线程之前需要同步数据,或者一个线程处理后的的数据,需要给另外一个线程进行处理,这就需要线程之间进行通讯,多线程间的通信和同步是通过操作系统提供的API实现的。下面是常见的线程间通信和同步机制:
互斥量(Mutexes):用于保护临界区,防止多个线程同时访问共享资源造成的数据不一致。POSIX线程库中的pthread_mutex_t类型可用于创建和管理互斥锁。
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
pthread_mutex_lock(&mutex); // 进入临界区前加锁
// 访问共享资源的代码
pthread_mutex_unlock(&mutex); // 退出临界区后解锁
条件变量(Condition Variables):配合互斥量使用,允许一个线程等待特定条件发生后再继续执行。例如,当队列为空时,生产者线程等待消费者线程发出通知。
pthread_cond_t cond;
pthread_mutex_t mutex;
pthread_cond_init(&cond, NULL);
pthread_mutex_lock(&mutex);
while (queue_is_empty()) { // 检查条件
pthread_cond_wait(&cond, &mutex); // 条件不满足则等待
}
// 条件满足,处理数据
pthread_mutex_unlock(&mutex);
信号量(Semaphores):是一种更通用的同步原语,可以用来控制对有限资源的访问数量。POSIX中有sem_t类型的信号量。
sem_t semaphore;
sem_init(&semaphore, 0, MAX_THREADS); // 初始化信号量,设置最大并发数
sem_wait(&semaphore); // 请求资源,若资源不足则阻塞
// 使用资源
sem_post(&semaphore); // 释放资源
事件(Events or Binary Semaphores):在Windows API中,事件对象可以用来指示某个状态的发生,线程可以等待这个状态改变。
HANDLE event = CreateEvent(NULL, FALSE, FALSE, NULL); // 创建手动重置事件,初始状态为未触发
WaitForSingleObject(event, INFINITE); // 等待事件被触发
SetEvent(event); // 触发事件
ResetEvent(event); // 重置事件状态
消息队列(Message Queues):虽然不是所有C语言环境都支持,但在某些系统如Windows下,线程可以通过消息队列进行通信。一个线程向队列发送消息,另一个线程从队列接收并处理这些消息。
// Windows API 示例
PostThreadMessage(threadId, WM_USER, wParam, lParam); // 向指定线程的消息队列发送消息
MSG msg;
GetMessage(&msg, NULL, 0, 0); // 接收消息
共享内存(Shared Memory):虽然不是直接的通信方式,但通过全局或共享内存区域,不同线程可以交换数据。需要注意的是,即使使用了共享内存,也必须结合上述同步原语来保证操作的原子性和一致性。
每种方法都有其适用场景,在实际编程中,在保证线程通讯的同时,也要保证通讯数据的一致性。