操作系统实验:进程和线程同步和互斥(生产者消费者问题,睡觉的理发师问题)

1.生产者消费者问题(信号量)

参考教材中的生产者消费者算法,创建5个进程,其中两个进程为生产者进程,3个进程为消费者进程。一个生产者进程试图不断地在一个缓冲中写入大写字母,另一个生产者进程试图不断地在缓冲中写入小写字母。3个消费者不断地从缓冲中读取一个字符并输出。为了使得程序的输出易于看到结果,仿照的实例程序,分别在生产者和消费者进程的合适的位置加入一些随机睡眠时间。

可选的实验:在上面实验的基础上实现部分消费者有选择地消费某些产品。例如一个消费者只消费小写字符,一个消费者只消费大写字母,而另一个消费者则无选择地消费任何产品。消费者要消费的产品没有时,消费者进程被阻塞。注意缓冲的管理。

【参考代码】 

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <random>
using namespace std;

const int n = 10; // 缓冲区大小
queue<char> buffer; // 缓冲区
mutex mtx; // 互斥锁
condition_variable empty, da, xiao; // 条件变量
int flag = -1; // 标志位

// 生产者线程A,生成大写字符
void produce_A() 
{
    while (true) {
        unique_lock<std::mutex> lock(mtx);
        empty.wait(lock, [] { return buffer.size() < n; }); // 等待缓冲区非满
        char ch = 'A' + std::rand() % 26; // 生成大写字符
        buffer.push(ch); // 将字符放入缓冲区
        da.notify_one(); // 通知消费者有大写字符可用
        sleep(1);
    }
}
// 生产者线程a,生成小写字符
void produce_a() 
{
    while (true) {
        unique_lock<std::mutex> lock(mtx);
        empty.wait(lock, [] { return buffer.size() < n; }); // 等待缓冲区非满
        char ch = 'a' + std::rand() % 26; // 生成小写字符
        buffer.push(ch); // 将字符放入缓冲区
        xiao.notify_one(); // 通知消费者有小写字符可用
        sleep(1);
    }
}
// 消费者线程A,处理大写字符
void consumer_A() 
{
    while (true) {
        unique_lock<std::mutex> lock(mtx);
        da.wait(lock, [] { return !buffer.empty(); }); // 等待有大写字符可用
        char ch = buffer.front(); // 从缓冲区取出字符
        buffer.pop(); // 移除字符
        empty.notify_one(); // 通知生产者缓冲区有空位
        cout << "Consumer A: " << ch << std::endl; // 输出字符
        sleep(1);
    }
}
// 消费者线程a,处理小写字符
void consumer_a() 
{
    while (true) {
        unique_lock<std::mutex> lock(mtx);
        xiao.wait(lock, [] { return !buffer.empty(); }); // 等待有小写字符可用
        char ch = buffer.front(); // 从缓冲区取出字符
        buffer.pop(); // 移除字符
        empty.notify_one(); // 通知生产者缓冲区有空位
        cout << "Consumer a: " << ch << std::endl; // 输出字符
        sleep(1);
    }
}
// 消费者线程A或a,处理大写或小写字符
void consumer_A_or_a()
{
    while (true) {
        unique_lock<std::mutex> lock(mtx);
        da.wait(lock, [] { return !buffer.empty(); }); // 等待有大写字符可用
        char ch = buffer.front(); // 从缓冲区取出字符
        buffer.pop(); // 移除字符
        empty.notify_one(); // 通知生产者缓冲区有空位
        cout << "Consumer A or a: " << ch << std::endl; // 输出字符
        sleep(1);
    }
}

int main()
{
    thread producerA(produce_A);
    thread producera(produce_a);
    thread consumerA(consumer_A);
    thread consumera(consumer_a);
    thread consumerAora(consumer_A_or_a);

    producerA.join();
    producera.join();
    consumerA.join();
    consumera.join();
    consumerAora.join();
    return 0;
}

【运行结果】

1、竞争不是很明显 2、某些进程消费了错误的产品

2.实现睡觉的理发师问题(同步互斥方式采用信号量或mutex方式均可)

理发师问题的描述:一个理发店接待室有n张椅子,工作室有1张椅子;没有顾客时,理发师睡觉;第一个顾客来到时,必须将理发师唤醒;顾客来时如果还有空座的话,他就坐在一个座位上等待;如果顾客来时没有空座位了,他就离开,不理发了;当理发师处理完所有顾客,而又没有新顾客来时,他又开始睡觉。

【参考代码】 线程实现睡觉的理发师问题(mutex方式)icon-default.png?t=N7T8http://t.csdnimg.cn/JNRne

#include <bits/stdc++.h>
#include <pthread.h>
#include <unistd.h>
using namespace std;

pthread_mutex_t Mutex;
int n;
int num;
int flag = -1;

void *customer(void *arg)
{
	while(flag){
		pthread_mutex_lock(&Mutex);
		if(num < n)
		{
			num++;
			cout << "A customer IN, chairs left:" << n - num << endl;
			pthread_mutex_unlock(&Mutex); //解锁
		}
		else
		{
			pthread_mutex_unlock(&Mutex); //解锁
			cout << "No chairs!" << endl;
		}
	}
}

void *barber(void *arg){
	while(flag){
		if(num > 0)
		{
			pthread_mutex_lock(&Mutex);
			num--;
			cout << "A customer OUT, chairs left:" << n-num << endl;
			pthread_mutex_unlock(&Mutex); //解锁
		}
	}
}

int main()
{
 	cout << "input chairs number:" << endl;
 	cin>>n;
 	num = 0;
 	pthread_t Barber, Customer;
 	pthread_mutex_init(&Mutex, NULL);
 	pthread_create(&Barber, NULL, barber, NULL);
 	pthread_create(&Customer, NULL, customer, NULL);
 	sleep(1);
 	flag = 0;
 	pthread_join(Barber, NULL);
 	pthread_join(Customer, NULL);
 	pthread_mutex_destroy(&Mutex);
 	return 0;
}

 【运行结果】

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《生产者与消费者问题算法实现》 设计思想 因为有多个缓冲区,所以生产者线程没有必要在生成新的数据之前等待最后一个数据被消费者线程处理完毕。同样,消费者线程并不一定每次只能处理一个数据。在多缓冲区机制下,线程之间不必互相等待形成死锁,因而提高了效率。   多个缓冲区就好像使用一条传送带替代托架,传送带上一次可以放多个产品。生产者在缓冲区尾加入数据,而消费者则在缓冲区头读取数据。当缓冲区满的时候,缓冲区就上锁并等待消费者线程读取数据;每一个生产或消费动作使得传送带向前移动一个单位,因而,消费者线程读取数据的顺序和数据产生顺序是相同的。 可以引入一个count计数器来表示已经被使用的缓冲区数量。用hNotEmptyEvent 和hNotFullEvent 来同步生产者和消费者线程。每当生产者线程发现缓冲区满( count=BufferSize ),它就等待hNotEmptyEvent 事件。同样,当消费者线程发现缓冲区空,它就开始等待hNotEmptyEvent。生产者线程写入一个新的数据之后,就立刻发出hNotEmptyEvent 来唤醒正在等待的消费者线程;消费者线程在读取一个数据之后,就发出hNotFullEvent 来唤醒正在等待的生产者线程。 程序的设计思想大致为:设置一while循环,pi生产者访问临界区,得到权限访问缓冲区,如果缓冲区满的,则等待,直到缓冲区非满;访问互斥锁,当得到互斥锁且缓冲区非满时,跳出while循环,开始产生新数据,并把数据存放于Buffer缓冲区中,当数据存放结束则结束临界区;接着唤醒消费者线程;ci消费者访问临界区,得到权限访问缓冲区,如果缓冲区为空,没有可以处理的数据,则释放互斥锁且等待,直到缓冲区非空;当等到缓冲区非空时,跳出while循环;消费者获得数据,并根据所获得的数据按类别消费(当消费者获得的数据为大写字母时,则把大写字母转换成小写字母,并显示;当消费者获得的数据为小写字母时,则把小写字母转换成大写字母,并显示;当消费者获得的数据为字符0、1、2、……8、9时,把这些字符直接显示到屏幕;当消费者获得的数据为符号(+、-、*、\……)时,把这些符号打印成7行7列的菱形);处理完数据后,结束临界区;接着唤醒生产者线程

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值