在 Linux 多线程编程中,条件变量是一种用于线程间同步的重要机制。它通常与互斥锁结合使用,用于解决多个线程竞争共享资源的问题。条件变量允许一个线程在等待某个条件变为真时阻塞,并且在另一个线程改变条件并通知时恢复执行。这个玩意跟内核等待队列差不多意思。
在 Linux 多线程编程中,使用条件变量进行线程同步通常涉及以下几个相关的函数:
pthread_cond_init: 该函数用于初始化条件变量。 原型为 int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)。 参数 cond 是要初始化的条件变量,attr 是条件变量的属性,通常为 NULL。pthread_cond_destroy: 用于销毁条件变量。 原型为 int pthread_cond_destroy(pthread_cond_t *cond)。 参数 cond 是要销毁的条件变量。pthread_cond_wait: 该函数用于等待条件变量的状态发生变化。 原型为 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)。 参数 cond 是要等待的条件变量,mutex 是与条件变量配合使用的互斥锁。在调用该函数时,线程会释放互斥锁并阻塞,直到条件变量被其他线程发出信号唤醒。pthread_cond_timedwait: 类似于 pthread_cond_wait,但是可以设置超时时间,防止永久等待。 原型为 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)。pthread_cond_signal: 该函数用于发送信号给等待条件变量的一个线程。 原型为 int pthread_cond_signal(pthread_cond_t *cond)。调用该函数会唤醒等待队列中的一个线程。pthread_cond_broadcast: 类似于 pthread_cond_signal,但会唤醒等待队列中的所有线程。 原型为 int pthread_cond_broadcast(pthread_cond_t *cond)。
条件变量demo:
在此demo中,有一个生产者线程和一个消费者线程,它们共享一个整数变量 shared_data。生产者线程周期性地增加 shared_data 的值,而消费者线程在 shared_data 不为零时消费一个数据。生产者在生产了一个数据后会发送信号通知消费者线程,消费者在消费数据时需要先检查条件是否满足,如果不满足,则等待条件变为真。
#include <stdio.h> #include <pthread.h> #include <unistd.h>pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int shared_data = 0;void* producer(void* arg) {while (1) {pthread_mutex_lock(&mutex);shared_data++; // 生产一个数据printf("Produced: %d\n", shared_data);pthread_cond_signal(&cond); // 发送信号通知消费者pthread_mutex_unlock(&mutex);sleep(1); // 生产者休眠1秒 }return NULL; }void* consumer(void* arg) {while (1) {pthread_mutex_lock(&mutex);while (shared_data == 0) { // 等待条件变为真pthread_cond_wait(&cond, &mutex);}printf("Consumed: %d\n", shared_data);shared_data--; // 消费一个数据pthread_mutex_unlock(&mutex);}return NULL; }int main() {pthread_t producer_thread, consumer_thread;pthread_create(&producer_thread, NULL, producer, NULL);pthread_create(&consumer_thread, NULL, consumer, NULL);pthread_join(producer_thread, NULL);pthread_join(consumer_thread, NULL);return 0; }