经典同步互斥问题

概念理解

互斥:只能有一个进程访问共享资源或只能有一个线程访问临界区

同步:多个进程间的协作关系。进程A的执行需要等待进程B事件执行完成

异步:进程以不可预知的速度向前推进。在等待某事件的过程中,继续做自己的事,不需要等待事件完成后工作,通过线程实现

并发:进程间走走停停运行(在一个时间点上只运行一个进程,在一个时间段运行多个进程)

并行:多核处理器同时运行多个进程(在一个时间点上可以运行多个进程)

🔧经典同步互斥问题

🎋生产者-消费者问题

条件:

  1. 在任何时候只能有一个线程可以操作共享变量
  2. 允许同一时间有多个生产者或者多个消费者
  3. 当食物为0,需要等待生产者生产;当食物满了,需要等待消费者消费

解决方法

  1. 信号量
  2. 管程

在这里插入图片描述

//使用信号量解决同步互斥问题
Class BoundedBuffer{
	mutex = new Semaphore(1);
	fullBuffers = new Semaphore(0);
	emptyBuffers = new Semaphore(n);
}
 
BounderBuffer::Deposit(c){
	emptyBuffers->P();     //解决同步问题
	mutex->P();           //解决互斥问题
	Add e to the buffer;
	mutex->V();
	fullBuffers->V();
}

BoundedBuffer::Remove(c){
	fullBuffers->P();
	mutex->P();
	Remove e from buffer;
	mutex->V();
	emptyBuffers->V();
}
//使用管程实现同步互斥问题
Class BoundedBuffer{
	Lock lock;
	int count = 0;
	Condition notFull,notEmpty;
}

BoundedBuffer::Deposit(e){
    lock->Acquire();    //解决互斥问题
    while(count == n){   //解决同步问题,唤醒后先release再执行其他线程
        notFull.Wait(&lock);
    }
    Add c to the buffer;
    count++;
    notEmpty.Signal();
    lock->Release();
}

BoundedBuffer::Remove(e){
    lock->Acquire();
    while(count == 0 ){
        notEmpty.Wait(&lock);
    }
    Remove c from buffer;
    count--;
    notFull.Signal();
    lock->Release();
}

🖊️读者-写者问题

条件:

  1. 在任何时候只能有一个线程可以操作共享变量
  2. 允许同一时间有多个读者,但在任何时候只有一个写者
  3. 写者在读者后面:写者需要等待读者读完;读者在写者后面:读者优先,因为读者不改变数据

解决方法

  1. 信号量
  2. 管程

在这里插入图片描述

//使用信号量解决同步互斥问题(读者优先)
Class BoundedBuffer{
	int Rcount = 0;     //读者的数量
	CountMutex = new Semaphore(1);
	WriteMutex = new Semaphore(1);
}

BoundedBuffer::Write(){
	sem_wait(WriteMutex);
	
	write;
	
	sem_post(WriteMutex);
}  

BoundedBuffer::Read(){
	sem_wait(CountMutex);
	if(Rcount == 0){
		sem_wait(WriteMutex);
	}
	Rcount++;
	sem_post(CountMutex);
	
	read;
	
	sem_wait(CountMutex);
	Rcount--;
	if(Rcount == 0){
		sem_post(WriteMutex);
	}
	sem_post(CountMutex);
}
//使用管程解决同步互斥问题(写者优先)
Class BoundedBuffer{
	AR = 0;    //active readers
    AW = 0;	   //active writers
    WR = 0;    //waiting readers
    WW = 0;    //waiting writers
    Condition okToRead;
    Condition okToWrite;
    Lock lock;
}

BuffedBuffer::Write(){
    lock.Acquire();
    while((AW+AR)>0){   //等待没有写者写和没有读者读,再进行写操作
        WW++;
        okToWrite.wait(&lock);
        WW--;
    }
    AW++;
    lock.Release();
    
    write;
    
    lock.Acquire();
    AW--;
    if(WW>0){        //写者优先,先唤醒等待队列中的写者
        okToWrite.signal();
    }else if(WR>0){       //没有等待的写者,再唤醒等待的读者
        okToRead.broadcast();
    }
    lock.Release();
}

BuffedBuffer::Read(){
    lock.Acquire();       //等待没有写者,再进行读操作
    while((AW+WW)>0){
        WR++;
        okToRead.wait(&lock);
        WR--;
    }
    AR++;
    lock.Release();
    
    read;
    
    lock.Acquire();     //等待没有正在读的读者,再唤醒写线程
    AR--;
    if(AR == 0 && WW > 0){
        okToWrite.signal();
    }
    lock.Release();
}

🍽️哲学家就餐问题

​ 圆桌上有5个哲学家,每个哲学家之间都有一把叉子。哲学家有思考进餐两个动作,进餐时需要同时拿起左右两边的叉子,思考时则同时放下叉子。如何保证哲学家动作有序进行?

在这里插入图片描述

Class BoundedBuffer{
	int state[N];     //记录每个人的状态
	mutex = new Semaphore(1);     //互斥信号量
	s[N] = new Semaphore(0);    //同步信号量
}

void philosopher(int i){
	while(TRUE){
		think();
		take_forks(i);
		eat();
		put_forks(i);
	}
}

void take_forks(int i){
	P(mutex);
	state[i] = HUNGRY;
	test_take_left_right_forks(i);
	V(mutex);
	P(s[i]);      //没有叉子便阻塞
}

void put_forks(int i){
    P(mutex);
	state[i] = THINKING;
	test_take_left_right_forks(LEFT);
	test_take_left_right_forks(RIGHT);
    V(mutex);
}

void test_take_left_right_forks(int i){
	if(state[i] == HUNGRY &&  state[LEFT] != EATING && state[RIGHT] != EATING){
		state[i] = EATING;
		V(s[i]);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值