1.提出问题
在纯互斥环境下,线程会产生饥饿问题;每个线程如果申请不到锁,就会进入阻塞,当特定情况下被唤醒(全部唤醒),线程之间是没有一定的顺序的。
**如果在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,这就是同步!**它能解决线程饥饿问题,能按照一定的顺序让线程完成工作。
2.条件变量
同步是在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源;条件变量是实现同步的一种机制,既然要保证数据安全那么就要有互斥锁,当线程首先访问到对应的锁资源,如果申请不到,再去对应的条件变量的队列中排队,所以条件变量必须依赖锁的使用!
当一个线程退出临界区,对应的条件条件变量就通知队列中的线程,唤醒一个或者一批!
张三(线程)进入自习室(临界区)自习,并反锁门,其他人(其他线程)也去自习先自习室门口找钥匙(先申请锁),发现有人,就去排队。当张三离开自习室,将钥匙放在门口(释放锁),并敲一下铃铛让其他的人自习。
所以至少看了来条件变量有两个东西,1.按照一定顺序排队的数据结构,2.有对用的通信机制,唤醒队列等待的线程。
条件变量是一个概念(任何计算机中的概念),落实到对应的代码实现上先描述再组织。
3.条件变量接口与使用
初始化条件变量
- 方法一:静态分配
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
- 方法二:动态分配
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrictattr);
参数:
cond:要初始化的条件变量
attr:NULL
销毁
int pthread_cond_destroy(pthread_cond_t *cond)
注意:静态分配的条件变量不用自己手动销毁
等待条件满足
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
参数:
cond:要在这个条件变量上等待
mutex:互斥量
唤醒等待
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond)
快速实现
#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
int g_val = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void* count1(void * args)
{
pthread_detach(pthread_self());
uint64_t num = *(uint64_t*)args;
while(true)
{
// 这个地方不对临界资源加锁保护是不行的!
cout << "pthread num is : " << num << " : the add of g_val number is : " << g_val++ << endl;
// 休眠一下,不然会有饥饿问题
sleep(1);
}
}
void test1()
{
// 1.多线程对一个全局的变量修改(这是有问题的例子)
// 这里是64位系统,避免(void*)i警告用uint64_t
for(uint64_t i = 0;i < 5; i++)
{
pthread_t pid;
// 这里i传入地址,是由问题的,如果不是堆上的空间不要传地址,i传地址改变也是共享资源会有并发问题
pthread_create(&pid,nullptr,count1,(void*)&i);
}
while(true){}
}
void* count2(void* args)
{
uint64_t num = (uint64_t)args;
while(true)
{
pthread_mutex_lock(&lock);
/*
这个地方:满足条件就去条件变量下等待!所以说让一个线程去休眠,是临界资源(临界资源也是有状态的)不就绪。
怎么知道临界资源是就绪还是不就绪的?判断出来的!判断是访问临界资源吗?必须是的,也就是判断必须在加锁之后!!!
pthread_cond_wait让线程等待的时候,会自动释放锁!
其他线程来的时候再去竞争锁,pthread_mutex_lock(&lock);锁竞争完之后pthread_cond_wait(&cond,&lock);这里添加变量的条件总是满足的
一上来就去条件变量下排队,等待唤醒(pthread_cond_signal(默认唤醒第一个)或pthread_cond_broadcast(唤醒一批))
*/
pthread_cond_wait(&cond,&lock);
cout << "pthread num is : " << num << " : the add of g_val number is : " << g_val++ << endl;
pthread_mutex_unlock(&lock);
}
}
void test2()
{
for(uint64_t i = 0;i < 5;i++)
{
pthread_t pid;
pthread_create(&pid,nullptr,count2,(void*)i);
}
cout << "create thread success !" << endl;
sleep(3);
while(true)
{
sleep(1);
// 唤醒:pthread_cond_signal(默认唤醒第一个)或pthread_cond_broadcast(唤醒一批)
// pthread_cond_signal(&cond);
pthread_cond_broadcast(&cond);
cout << "signal thread~" << endl;
}
}
int main()
{
test2();
return 0;
}