条件变量(pthread_cond)是 C++ 多线程编程中的一种同步机制。它通常与互斥量(pthread_mutex)结合使用,用于实现线程间的协调与同步。
条件变量的作用是使线程能够等待某个条件的发生,并在条件满足时被唤醒。条件变量可以用来避免线程轮询等待某个事件的发生,从而提高线程的效率。
条件变量通常与互斥量一起使用。一个线程在等待某个条件时,它会先释放互斥量,然后进入等待状态。当另一个线程满足了这个条件,它会通过发送信号或广播信号的方式通知等待的线程,使得它从等待状态中醒来并重新获得互斥量,然后继续执行。
为什么需要将条件变量和互斥量一起使用
条件变量和互斥量在 C++ 多线程编程中经常一起使用,主要是为了保证线程安全和避免竞态条件等问题。
互斥量是一种用于保护共享资源的同步原语,用于防止多个线程同时访问共享资源而引起的竞争条件等问题。线程在访问共享资源之前需要获取互斥量,防止其他线程同时访问同一共享资源,从而保证线程安全。
条件变量则用于在线程之间传递信号和通知。线程在等待某个条件变量时,会先释放已经获取的互斥量,并进入等待状态。在等待期间,线程会阻塞并不占用 CPU 资源,直到有另一个线程发送信号或广播信号的时候,线程才会被唤醒,重新获得互斥量,并检查条件是否满足,从而决定是继续等待还是执行后续操作。
将条件变量和互斥量结合使用可以避免竞态条件和死锁等问题。在使用条件变量时,线程需要先获取互斥量,以确保线程安全。否则,在多线程环境下,可能会出现竞争条件等问题。同时,在等待条件变量时,线程需要先释放已经获取的互斥量,以避免死锁等问题。
因此,条件变量和互斥量的结合使用,可以使多线程程序更加安全和可靠。
下面是一个简单的例子,展示了条件变量的使用:
#include
#include
using namespace std;
pthread_mutex_t mutex;
pthread_cond_t cond;
int num = 0; //临界区
void* thread_func1(void* arg) { //线程1的main函数
pthread_mutex_lock(&mutex);
//在访问临界区资源之前先对互斥量解锁,访问或者修改完之后解锁
num++;
cout << "Thread1: num=" << num << endl;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
void* thread_func2(void* arg) { //线程2的main函数
pthread_mutex_lock(&mutex);
while (num == 0) { //当num==0时阻塞,在函数pthread_cond_wait内部会先释放mutex(不释放可能会导致死锁),当线程1发送信号之后线程2会从等待状态中醒来,继续向下执行
pthread_cond_wait(&cond, &mutex);
}
num--;
cout << "Thread2: num=" << num << endl;
pthread_mutex_unlock(&mutex);
}
int main() {
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, thread_func1, NULL);
pthread_create(&thread2, NULL, thread_func2, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
在这个例子中,我们创建了两个线程 thread1 和 thread2。其中,thread1 会先执行,它会将 num 的值加 1,并通过 pthread_cond_signal() 函数通知等待的线程。线程 thread2 在等待 num 的值变为非零的同时,通过 pthread_cond_wait() 函数进入等待状态。当线程 thread1 发送信号后,线程 thread2 会从等待状态中醒来,并执行 num 的减 1 操作。
注意,在等待条件变量时,线程需要先获取互斥量,以确保线程安全。否则,在多线程环境下,可能会出现竞争条件等问题。
pthread_cond_t; //条件变量类型
int pthread_cond_init(pthread_cond_t * restrict cond, const pthread_condattr_t * restrict attr);
//初始化一个条件变量
int pthread_cond_destroy(pthread_cond_t * restrict cond); //销毁一个条件变量
int pthread_cond_wait(pthread_cond_t * restrict cond, const pthread_mutexr_t * restrict mutex);
//函数的作用是将线程置于等待状态,并且在等待期间会释放 mutex 互斥量的锁,当线程被唤醒之后在重新取得互斥量的锁
int pthread_cond_timewait(pthread_cond_t * restrict cond, const pthread_mutexr_t * restrict mutex, const struct timespec *restrict abstime); //限时等待一个条件变量
int pthread_cond_signal(pthread_cond_t * restrict cond); //唤醒至少一个阻塞在条件变量上的线程
int pthread_cond_broadcast(pthread_cond_t * restrict cond); //唤醒全部阻塞在条件变量上的线程
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_mutex_init(&mutex, NULL); //NULL使用默认的属性
pthread_cond_init(&cond, NULL);
pthread_mutex_lock(&mutex);
while (条件不满足) {
pthread_cond_wait(&cond, &mutex);
}
**在等待条件变量时,线程需要先获取互斥量,以确保线程安全。**如果条件不满足,则线程调用 pthread_cond_wait() 函数进入等待状态,并释放已经获取的互斥量。在等待期间,线程会阻塞并不占用 CPU 资源。
pthread_mutex_lock(&mutex);
// 满足条件后,发送信号或广播信号
pthread_cond_signal(&cond); // 或者 pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
在满足条件后,线程需要获取互斥量,并通过 pthread_cond_signal() 函数发送信号或通过 pthread_cond_broadcast() 函数广播信号。发送信号后,等待条件的线程将会从等待状态中醒来,并重新获得互斥量,以便执行后续操作。
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
注意,条件变量的使用需要和互斥量结合使用,以避免竞态条件等问题。在等待条件变量时,线程需要先获取互斥量,以确保线程安全。否则,在多线程环境下,可能会出现竞争条件等问题。