梳理前言
进程线程间的互斥相关背景概念:
- 临界资源:多线程执行流共享的资源就叫做临界资源
- 临界区:每个线程内部,访问临界资源的代码,就叫做临界区
- 互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用。
- 原子性:不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成。
- 死锁:两个或两个以上的进程(LWP)都在等待互相释放自己的资源,导致进程都不能继续执行的情形,称为死锁。
- 竞争条件:多个线程或进程在读写一个共享资源时的结果,依赖于他们执行的相对时间,这种情况叫做竞争。
- 饥饿:由于竞争条件不平等,与其他进程或线程竞争访问共享资源运行期间,被调度器无限忽视,无法访问共享资源的情况,称为饥饿。
梳理:
互斥:为了保证多个线程或进程访问同一份资源时,保证不产生数据二义性,用原子性的操作,去限制一部分线程的访问。
同步:为了保证各个线程之间互斥访问共享资源的顺序合理且高效,用条件变量和信号量(原子性操作)去安排访问顺序。
死锁:详情看上述概念,另外不是一定要两个以上的进程或线程才会死锁,一个也可以。看下面这种情形。
互斥量(锁)本身也是一种共享资源,如果一个线程中,申请了一把锁,在没有解锁的情况下,它又去申请这把锁,也会死锁,也就是自己等自己释放锁的情形。
饥饿:线程的创建时间有先后,调度器调度自然也有先后,如果我们不进行同步处理,先创建的线程很有可能就会一个人使用了共享资源,其他线程处于饥饿状态,这是不合理的。
互斥与同步
互斥量与条件变量
互斥量通常与条件变量一起使用,达到互斥与同步的效果。
生产者与消费者模型就是一个很好的例子。模拟实现一个
当然,如果只有一个生产者,那它也不需要和其他生产者竞争。
只有一个消费者,它也不需要和其他消费者竞争。
用队列来模拟上述商品为满或者为空的场景,同时有多个消费者和生产者。
#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include<unistd.h>
class mask
{
public:
int left;
int right;
public:
mask(int a=0,int b=0)
{
left=a;
right=b;
}
int add()
{
int c=left+right;
std::cout<<left<<"+"<<right<<"="<<c<<std::endl;
return c;
}
};
template<class T>
class block_queue
{
private:
std::queue<T> q;
int cap;
pthread_mutex_t lock;
pthread_cond_t empty;
pthread_cond_t full;
void lock_queue()
{
pthread_mutex_lock(&lock);
}
void unlock_queue()
{
pthread_mutex_unlock(&lock);
}
bool Is_full()
{
return q.size