1 为什么需要线程同步?
当多个线程同时访问共享资源时,可能会出现:
- 竞态条件:执行结果依赖于线程执行的顺序
- 数据不一致:线程读取到中间状态的数据
- 死锁:线程相互等待对方释放资源
2 同步概念与竞态条件
• 同步:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫做同步
• 竞态条件:因为时序问题,而导致程序异常,我们称之为竞态条件。在线程场景下,这种问题也不难理解
3 条件变量
• 当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。
• 例如一个线程访问队列时,发现队列为空,它只能等待,等到其它线程将一个节点添加到队列中。这种情况就需要用到条件变量。
基本概念:
条件变量是多线程编程中的同步机制,用于线程间的通信和协调。它允许一个或多个线程等待某个条件成立,而其他线程在条件满足时通知等待的线程。
核心功能
1. 等待条件
- 线程检查条件,如果条件不满足,则进入等待状态
- 等待时会自动释放互斥锁,让其他线程能修改共享数据
2. 通知等待线程
- signal():唤醒一个等待线程
- broadcast():唤醒所有等待线程
3 条件变量函数
初始化
条件变量的初始化和互斥锁几乎一样
• 方法1,静态分配:
cpp
// 静态初始化(全局或静态变量)
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// 不需要调用 pthread_cond_init
// 也不需要调用 pthread_cond_destroy
方法2,动态分配: pthread_cond_init 函数
pthread_cond_init是 POSIX 线程库中用于初始化条件变量的函数。条件变量用于线程间的同步,允许线程等待某个条件成立。
cpp
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
参数说明
cond
- 指向要初始化的条件变量的指针
attr
- 指向条件变量属性的指针
- 如果为 NULL,则使用默认属性
返回值
- 成功:返回 0
- 失败:返回错误码(非零值)
销毁
cpp
int pthread_cond_destroy(pthread_1 cond_t *cond)
等待
pthread_cond_wait是 POSIX 线程(pthread)库中用于条件变量等待的函数。
cpp
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
参数说明
| 参数 | 说明 |
|---|---|
| cond | 指向条件变量的指针 |
| mutex | 指向互斥锁的指针 |
工作原理
1. 原子操作三部曲
当线程调用 pthread_cond_wait 时,它会原子地执行以下操作:
cpp
// 伪代码表示其行为:
pthread_mutex_unlock(mutex); // 1. 释放互斥锁
wait_for_signal(cond); // 2. 等待条件变量
pthread_mutex_lock(mutex); // 3. 重新获取互斥锁
2. 为什么要用互斥锁配合?
条件变量必须与互斥锁一起使用,原因:
- 防止竞争条件(race condition)
- 确保检查条件和等待是原子操作
- 避免信号丢失
唤醒等待
cpp
int pthread_cond_broadcast(pthread_cond_t *cond);//唤醒在该条件变量下等待的全部线程
//唤醒在该条件变量下等待的一个线程
int pthread_cond_signal(pthread_cond_t *cond);
代码实践:简单看一下函数应用
cpp
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *active(void *arg)
{
std::string name = static_cast<const char *>(arg);
while (true)
{
pthread_mutex_lock(&mutex);
pthread_cond_wait(&cond, &mutex);
std::cout << name << " 活动..." << std::endl;
pthread_mutex_unlock(&mutex);
}
}
int main(void)
{
pthread_t t1, t2;
pthread_create(&t1, NULL, active, (void *)"thread-1");
pthread_create(&t2, NULL, active, (void *)"thread-2");
sleep(3); // 可有可无,这里确保两个线程已经在运行
while (true)
{
// 对比测试
//pthread_cond_signal(&cond); // 唤醒一个线程
pthread_cond_broadcast(&cond); // 唤醒所有线程
sleep(1);
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
}

当唤醒一个线程时一个线程一个线程逐个出现,当唤醒所有线程时两个两个的一起出现