在 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; }