条件变量
1. 基本概念
条件变量是一种同步机制,它能够让一个线程等待另一个线程满足特定的条件。条件变量通常与互斥量配合使用,用于实现线程同步和通信。
在 Linux 系统中,条件变量是通过 pthread_cond_t
类型来表示的。
对于条件变量,一般来说,操作步骤如下:
- 调用
pthread_cond_init()
函数初始化条件变量。 - 获取互斥量。
- 检查某个条件是否满足。
- 如果满足,则执行相应的操作。
- 如果不满足,则调用
pthread_cond_wait()
函数等待条件变量。 - 当收到通知后,继续检查条件是否满足,并重复以上操作。
- 释放互斥量。
- 调用
pthread_cond_destroy()
函数销毁条件变量。
2. 条件变量API
2.1 定义条件变量并初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // 定义条件变量
这种方法等价于使用 pthread_cond_init()
函数初始化条件变量,但是更加简洁。
注意:使用PTHREAD_COND_INITIALIZER宏初始化条件变量时,需要保证该读写锁变量是全局变量或者静态变量。
2.2 初始化条件变量
pthread_cond_init()
函数用于初始化条件变量。函数原型为:
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
该函数接受两个参数:
cond
:指向条件变量的指针。attr
:指向条件变量属性的指针。如果初始化成功,则该函数返回 0。否则,返回一个非 0 值。
注意:在调用该函数时,条件变量默认处于未被通知的状态。在初始化后,线程可以通过调用 pthread_cond_wait()
函数等待条件变量的通知。另一个线程可以调用 pthread_cond_signal()
函数来通知条件变量。
2.3 销毁条件变量
pthread_cond_destroy()
函数用于销毁条件变量。函数原型为:
int pthread_cond_destroy(pthread_cond_t *cond);
该函数接受一个参数:
cond
:指向条件变量的指针。如果销毁成功,则该函数返回 0。否则,返回一个非 0 值。
注意:调用 pthread_cond_destroy()
函数后,条件变量将不能再使用,如果还有线程等待该条件变量,则会收到一个错误。因此,通常在销毁条件变量前,应该先通知所有等待该条件变量的线程,然后再调用该函数。
2.4 等待队列
pthread_cond_wait()
函数用于让线程等待条件变量的通知。当线程调用该函数时,它会释放关联的互斥锁,然后阻塞,直到另一个线程调用 pthread_cond_signal()
或 pthread_cond_broadcast()
函数来通知该线程。当线程被唤醒时,它会再次获得互斥锁。
函数原型为:
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
该函数接受两个参数:
cond
:指向条件变量的指针。mutex
:指向关联的互斥锁的指针 。如果线程被成功唤醒,则该函数返回 0。如果发生错误,则返回一个非 0 值。
注意:在调用该函数时,线程必须已经获得了关联的互斥锁。否则,程序的行为是未定义的。
2.5 唤醒条件队列(单个)
pthread_cond_signal()
函数用于通知条件变量,唤醒正在等待该条件变量的线程。函数原型为:
int pthread_cond_signal(pthread_cond_t *cond);
该函数接受一个参数:
cond
:指向条件变量的指针。如果唤醒操作成功,则该函数返回 0。如果发生错误,则返回一个非 0 值。
注意:该函数仅会唤醒一个正在等待条件变量的线程。如果有多个线程正在等待条件变量,则必须调用该函数多次才能唤醒所有线程。另一个选项是使用 pthread_cond_broadcast()
函数,该函数可以一次性唤醒所有正在等待条件变量的线程。
2.6 唤醒条件队列(全部)
pthread_cond_broadcast()
函数用于通知条件变量,唤醒所有正在等待该条件变量的线程。函数原型为:
int pthread_cond_broadcast(pthread_cond_t *cond);
该函数接受一个参数:
cond
:指向条件变量的指针。如果唤醒操作成功,则该函数返回 0。如果发生错误,则返回一个非 0 值。
注意:该函数会一次性唤醒所有正在等待条件变量的线程。如果只想唤醒一个线程,则可以使用 pthread_cond_signal()
函数。
3. 示例代码
下面这段代码创建了两个线程,thread1
和 thread2
,然后等待它们完成。thread1
等待一个条件变量,直到 thread2
向它发出信号。当 thread1
收到信号时,它会打印一条消息,然后退出。thread2
也会打印一条消息并退出。
代码使用互斥锁和条件变量来同步两个线程。互斥锁用于保护对共享变量 flag
的访问,条件变量用于等待 thread2
设置 flag
。当 thread2
设置了 flag
,它会发出信号,唤醒 thread1
继续执行。
#include <pthread.h>
#include <stdio.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
int flag = 0;
void *thread1(void *arg)
{
pthread_mutex_lock(&mutex); // 获取互斥锁
while (flag == 0)
pthread_cond_wait(&cond, &mutex); // 等待条件变量
pthread_mutex_unlock(&mutex); // 释放互斥锁
printf("Thread 1\n");
pthread_exit(NULL);
}
void *thread2(void *arg)
{
pthread_mutex_lock(&mutex); // 获取互斥锁
flag = 1;
pthread_cond_signal(&cond); // 发送信号
pthread_mutex_unlock(&mutex); // 释放互斥锁
printf("Thread 2\n");
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
pthread_mutex_init(&mutex, NULL); // 初始化互斥锁
pthread_cond_init(&cond, NULL); // 初始化条件变量
pthread_t t1, t2;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_cond_destroy(&cond); // 销毁条件变量
pthread_mutex_destroy(&mutex); // 销毁互斥锁
return 0;
}