一组进程中的各个进程均占有不会释放的资源
,但因互相申请被其他进程所站用不会释放的资源而处于的一种永久等待状态。互斥条件
:一个资源每次只能被一个执行流使用请求与保持条件
:一个执行流因请求资源而阻塞时,对已获得的资源保持不放不剥夺条件
:一个执行流已获得的资源,在末使用完之前,不能强行剥夺循环等待条件
:若干执行流之间形成一种头尾相接的循环等待资源的关系注意
:要形成死锁,四个条件缺一不可。所以解决死锁的方法就是破坏四个必要条件中的一个以上,常见有银行家算法/死锁检测算法
等。
问题:
同步
:在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫做同步。竞态条件
:因为时序问题,而导致程序异常,我们称之为竞态条件。在线程场景下,这种问题也不难理解。int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
参数
:
int pthread_cond_destroy(pthread_cond_t *cond)
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
参数
:
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
#include
#include
#include
pthread_mutex_t lock;//创建锁
pthread_cond_t cond;//创建环境变量
void *run1(void *arg)//负责等待线程二发来信号开始执行
{
const char *name=(char*)arg;
while(1)
{
pthread_cond_wait(&cond,&lock);//等待
printf("%s get singal\n",name);
}
}
void *run2(void *arg)//负责给线程一发送信号
{
const char *name=(char*)arg;
while(1)
{
sleep(2);
pthread_cond_signal(&cond);//唤醒等待
printf("%s signal done!\n",name);
}
}
int main()
{
pthread_mutex_init(&lock,NULL);//初始化锁
pthread_cond_init(&cond,NULL);//初始化环境变量
pthread_t t1;
pthread_t t2;
pthread_create(&t1,NULL,run1,"thread1");//创造两个新线程
pthread_create(&t2,NULL,run2,"thread2");
pthread_join(t1,NULL);//等待两个线程退出
pthread_join(t2,NULL);
pthread_mutex_destroy(&lock);//销毁锁
pthread_cond_destroy(&cond);//销毁环境变量
return 0;
}
为什么pthread_cond_wait()需要互斥量呢
?问题:
生产者消费者模型优点:
生产者消费者“321”
3种关系
:生产者&消费者(互斥/同步),生产者&生产者(互斥),消费者&消费者(互斥)2种角色
:生产者,消费者一个交易场所
ps.h
#ifndef __QUEUE_BLOCK_H__
#define __QUEUE_BLOCK_H__
#include
#include
#include
#include
using namespace std;
class Task
{
public:
int x;
int y;
public:
Task(int _x,int _y):x(_x),y(_y)
{
}
Task()
{
}
int Run()
{
return x+y;
}
~Task()
{
}
};
class BlockQueue
{
private:
queue<Task> q;
size_t cap;
pthread_mutex_t lock;
pthread_cond_t c_cond;
pthread_cond_t p_cond;
public:
//判满
bool IsFull()
{
return q.size()>=cap;
}
//判空
bool IsEmpty()
{
return q.empty();
}
//解锁
void UnlockQueue()
{
pthread_mutex_unlock(&lock);
}
//唤醒消费者
void WakeUpConsumer()
{
cout<<"WakeUpConsumer"<<endl;
pthread_cond_signal(&c_cond);
}
//唤醒生产者
void WakeUpProductor()
{
cout<<"WakeUpProductor"<<endl;
pthread_cond_signal(&p_cond);
}
//pthread_cond_wait传入lock参数:
//在条件满足时,消费者or生产者持有锁进入临界区执行,当判断条件不满足时,调用对应的wait函数
//在消费者or生产者等待时,调用对应的Wait函数,自动释放lock
//消费者等待,必须解锁,让另一个角色持有锁,以保证线程之间友好,在
void ConsumerWait()
{
cout<<"ConsumerWait"<<endl;
pthread_cond_wait(&c_cond,&lock);
}
//生产者等待
void ProductWait()
{
cout<<"ProductWait"<<endl;
pthread_cond_wait(&p_cond,&lock);
}
public:
BlockQueue(int _cap):cap(_cap)
{
pthread_mutex_init(&lock,nullptr);
pthread_cond_init(&c_cond,nullptr);
pthread_cond_init(&p_cond,nullptr);
}
~BlockQueue()
{
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&p_cond);
pthread_cond_destroy(&c_cond);
}
//消费者消费,拿取or执行队列中的数据以及任务并执行
void Put(Task in)
{
UnlockQueue();
if(IsFull())
{
WakeUpConsumer();
ProductWait();
}
q.push(in);
UnlockQueue();
}
//生产者生产,向队列中塞数据或者任务
void Get(Task &out)
{
UnlockQueue();
if(IsEmpty())
{
WakeUpProductor();
ConsumerWait();
}
out=q.front();
q.pop();
UnlockQueue();
}
};
#endif
ps.cpp
#include "block.h"
using namespace std;
void *consumer_run(void *arg)
{
//int num=(int)arg;
pthread_mutex_t lock;
BlockQueue *bq=(BlockQueue*)arg;
while(true)
{
pthread_mutex_lock(&lock);
//int data;
Task t;
bq->Get(t);
//t.Run();
pthread_mutex_unlock(&lock);
cout<<"consumer"<<t.x<<"+"<<t.y<<"="<<t.Run()<<endl;
sleep(1);
}
//pthread_mutex_unlock(&lock);
}
void *productor_run(void *arg)
{
//int num=(int)arg;
pthread_mutex_t lock;
sleep(1);
BlockQueue *bq=(BlockQueue*)arg;
//int count=0;
while(true)
{
int x=rand()%10+1;
int y=rand()%100+1;
pthread_mutex_lock(&lock);
Task t(x,y);
bq->Put(t);
pthread_mutex_unlock(&lock);
cout<<"productor "<<x<<"+"<<y<<"=?"<<endl;
}
//pthread_mutex_unlock(&lock);
}
int main()
{
BlockQueue *bq = new BlockQueue(5);
pthread_t con1,pro1;
pthread_create(&con1,nullptr,consumer_run,(void*)bq);
pthread_create(&pro1,nullptr,productor_run,(void*)bq);
//pthread_create(&con2,nullptr,consumer_run,(void*)bq);
//pthread_create(&pro2,nullptr,productor_run,(void*)bq);
pthread_join(con1,nullptr);
//pthread_join(con2,nullptr);
pthread_join(pro1,nullptr);
//pthread_join(pro2,nullptr);
return 0;
}
#include
int sem_init(sem_t *sem, int pshared, unsigned int value)
参数
:
int sem_destroy(sem_t *sem)
int sem_wait(sem_t *sem);
功能
:
int sem_post(sem_t *sem)//V()
功能
:
上面生产者-消费者的例子是基于queue的,其空间可以动态分配,现在基于固定大小的环形队列重写这个程序(POSIX信号量):
// RingQueue.hpp
#pragma once
#include
#include
#include
#include
#include
class RingQueue
{
private:
std::vector<int> _q;
int _cap;
//信号量
sem_t sem_blank;
sem_t sem_data;
//资源下标
int pro_sub;
int con_sub;
private:
void P(sem_t &sem)
{
sem_wait(&sem);
}
void V(sem_t &sem)
{
sem_post(&sem);
}
public:
RingQueue(int cap=6)
:_cap(cap)
,_q(cap)
{
sem_init(&sem_blank,0,_cap);//格子个数一开始为容量大小
sem_init(&sem_data,0,0);//数据一开始为0
pro_sub=0;
con_sub=0;
}
void Put(const int &data)
{
P(sem_blank);//申请格子资源,判断是否还有容量,格子--
_q[pro_sub]=data;
pro_sub++;
pro_sub%=_cap;//越界回环
V(sem_data);//数据++
}
void Get(int &data)
{
P(sem_data);//申请数据资源,判断是否还有数据,数据--
data=_q[con_sub];
con_sub++;
con_sub%=_cap;
V(sem_blank);//消耗数据,格子++
}
~RingQueue()
{
sem_destroy(&sem_blank);
sem_destroy(&sem_data);
pro_sub=con_sub=0;
}
};
//main.cpp
#include "RingQueue.hpp"
pthread_mutex_t pro_lock;//生产者组内竞争锁
pthread_mutex_t con_lock;//消费者组内竞争锁
int count=0;//生产者数据
void Lock(pthread_mutex_t &lock)
{
pthread_mutex_lock(&lock);
}
void ULock(pthread_mutex_t &lock)
{
pthread_mutex_unlock(&lock);
}
void *Get(void *arg)
{
RingQueue *q=(RingQueue*)arg;
while(1)
{
usleep(1);
int data=0;
Lock(con_lock);//组内竞争
q->Get(data);//获取数据
ULock(con_lock);
std::cout<<"consumer get data...:"<<data<<std::endl;
}
}
void *Put(void *arg)
{
RingQueue *q=(RingQueue*)arg;
while(1)
{
sleep(1);//增加系统调用
Lock(pro_lock);//组内竞争
int number = (++count)%10l;
q->Put(number);
ULock(pro_lock);
std::cout<<"productor put data...."<< number << std::endl;
}
}
int main()
{
//创建交易场所
RingQueue *q=new RingQueue(5);
//初始化锁
pthread_mutex_init(&con_lock,nullptr);
pthread_mutex_init(&pro_lock,nullptr);
//创建线程
pthread_t tid1,tid2,tid3,tid4,tid5,tid6;
pthread_create(&tid1,nullptr,Put,q);
pthread_create(&tid2,nullptr,Put,q);
pthread_create(&tid3,nullptr,Put,q);
pthread_create(&tid4,nullptr,Get,q);
pthread_create(&tid5,nullptr,Get,q);
pthread_create(&tid6,nullptr,Get,q);
//等待线程、避免内存泄漏,不关心返回值
pthread_join(tid1,nullptr);
pthread_join(tid2,nullptr);
pthread_join(tid3,nullptr);
pthread_join(tid4,nullptr);
pthread_join(tid5,nullptr);
pthread_join(tid6,nullptr);
//销毁工作
pthread_mutex_destroy(&con_lock);
pthread_mutex_destroy(&pro_lock);
delete q;
return 0;
}