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方式)http://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;
}