pthread 条件变量使用
- 条件变量:多线程中常用的一种同步机制。通常与互斥锁结合使用,用于实现线程之间的等待和通知机制。
- 条件变量提供了线程间的通信方式,其中一个线程可以等待某个条件满足,而另一个线程可以通知条件已经满足。
- 允许线程在某个特定的条件下进行等待,而不是占用 CPU 资源进行轮询检查。
- 通常用于解决生产者-消费者问题、读者-写者问题以及其他需要线程间同步的场景。
- 在使用条件变量时,需要搭配互斥锁以确保线程安全。当一个线程等待条件满足时,它会释放互斥锁,并等待其他线程通知。一旦收到通知,它会重新尝试获取互斥锁以进行后续操作。
- 在使用条件变量时要避免出现竞态条件(Race Condition),即在等待条件和接收通知之间可能发生的状态改变。因此,通常使用 while 循环来检查条件是否满足,而不是使用 if 语句。
pthread_cond_init
-
函数原型:
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict 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 *restrict cond, pthread_mutex_t *restrict mutex);
- cond:指向条件变量的指针。
- mutex:指向互斥锁的指针。
- 返回值:成功返回 0,失败返回错误代码。
-
用于等待条件变量被唤醒。
-
调用该函数之前,必须先获得互斥锁 mutex。
-
在等待期间,互斥锁会自动释放,并使当前线程处于阻塞状态,直到条件变量被唤醒并且重新获得互斥锁为止。
pthread_cond_timedwait
-
函数原型:
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
- cond:指向条件变量的指针。
- mutex:指向互斥锁的指针。
- abstime:指向结构体 timespec 的指针,表示等待的绝对时间。
- 返回值:成功返回 0,失败返回错误代码。
-
用于在指定的时间内等待条件变量被唤醒。如果在等待过程中条件变量被唤醒,则返回 0;如果等待超时,则返回 ETIMEDOUT;如果出现其他错误,则返回错误码。
-
调用该函数之前,必须先获得互斥锁 mutex。
-
在等待期间,互斥锁会自动释放,并使当前线程处于阻塞状态,直到条件变量被唤醒并且重新获得互斥锁为止。
pthread_cond_signal
-
函数原型:
int pthread_cond_signal(pthread_cond_t *cond);
- cond:指向条件变量的指针。
-
用于唤醒等待条件变量的一个线程。
-
如果有多个线程在等待条件变量,则会唤醒其中一个线程。
-
如果没有线程在等待条件变量,则该函数不会产生任何效果。
pthread_cond_broadcast
-
函数原型:
int pthread_cond_broadcast(pthread_cond_t *cond);
- cond:指向条件变量的指针。
-
用于唤醒所有等待条件变量的线程。
-
如果没有线程在等待该条件变量,则该函数不会产生任何效果。
示例
-
以下示例演示了条件变量的基本使用:一个线程更改变量值, 另一个线程等待变量值被更改后再使用。
#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <errno.h> #include <unistd.h> int var = 10; pthread_cond_t g_cond; pthread_mutex_t g_mutex; void* thread1_func(void* arg) { // 必须先获取互斥锁 pthread_mutex_lock(&g_mutex); sleep(1); var = 100; printf("thread1, change var to %d \n", var); // 解锁 pthread_mutex_unlock(&g_mutex); // 唤醒等待该条件变量的一个线程 pthread_cond_signal(&g_cond); return NULL; } void* thread2_func(void* arg) { // 必须先获取互斥锁 pthread_mutex_lock(&g_mutex); // 获取当前时间 struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); // 设置等待时间为 5 秒 ts.tv_sec += 5; // 等待条件变量被唤醒,或者等待时间超时 // 在等待期间,互斥锁会自动释放,并使当前线程处于阻塞状态,直到条件变量被唤醒并且重新获得互斥锁为止 printf("thread2, waiting cond signal\n"); int ret = pthread_cond_timedwait(&g_cond, &g_mutex, &ts); if (ret == 0) { // 条件变量被唤醒并且已经持有互斥锁 printf("thread2, get cond signaled\n"); } else if (ret == ETIMEDOUT) { printf("thread2, wait timed out\n"); } else { printf("thread2, wait failed\n"); } printf("thread2, get var %d\n", var); // 解锁 pthread_mutex_unlock(&g_mutex); return NULL; } int main() { // 初始化条件变量 pthread_cond_init(&g_cond, NULL); // 初始化互斥锁 pthread_mutex_init(&g_mutex, NULL); // 创建线程 pthread_t th1; pthread_t th2; pthread_create(&th2, NULL, thread2_func, NULL); // 让线程 2 先运行 sleep(1); pthread_create(&th1, NULL, thread1_func, NULL); // 等待线程结束 pthread_join(th1, NULL); pthread_join(th2, NULL); // 销毁互斥锁 pthread_mutex_destroy(&g_mutex); // 销毁条件变量 pthread_cond_destroy(&g_cond); return 0; }