一、生产者 - 消费者问题
问题描述:
一组生产者进程和一组消费者进程共享一个初始为空、大小为〃的缓冲区,只有缓冲区没满时,生产者才能把消息放入缓冲区,否则必须等待;只有缓冲区不空时,消费者才能从中取出消息,否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或一个消费者从中取出消息。
代码:
#include <Windows.h>
#include <iostream>
#include <stdlib.h>
typedef HANDLE Semaphore;
#define P(S) WaitForSingleObject(S, INFINITE)
#define V(S) ReleaseSemaphore(S, 1, NULL)
int produceId = 1000;
int consumeId;
int buf[10];
int BUFSIZE = 10;
int in = 0;
int out = 0;
Semaphore empty = CreateSemaphore(
NULL,
10,
10,
NULL
);
Semaphore mutex = CreateSemaphore(
NULL,
1,
1,
NULL
);
Semaphore full = CreateSemaphore(
NULL,
0,
10,
NULL
);
DWORD WINAPI Producer(LPVOID);
DWORD WINAPI Consumer(LPVOID);
VOID Produce();
VOID Consume();
VOID printbuf();
int main()
{
HANDLE produce;
HANDLE consumer1, consumer2, consumer3;
produce = CreateThread(
NULL,
0,
Producer,
NULL,
0,
NULL
);
consumer1 = CreateThread(
NULL,
0,
Consumer,
NULL,
0,
NULL
);
consumer2 = CreateThread(
NULL,
0,
Consumer,
NULL,
0,
NULL
);
consumer3 = CreateThread(
NULL,
0,
Consumer,
NULL,
0,
NULL
);
while (1)
{
WaitForSingleObject(produce, INFINITE);
WaitForSingleObject(consumer1, INFINITE);
WaitForSingleObject(consumer2, INFINITE);
WaitForSingleObject(consumer3, INFINITE);
}
return 0;
}
VOID printbuf() {
std::cout << "缓存中的数据:";
bool hasData = false;
for (int i = 0; i < BUFSIZE; i++) {
if (buf[i] != 0) {
std::cout << buf[i] << "----";
hasData = true;
}
}
if (hasData)
std::cout << std::endl;
else
std::cout << "无" << std::endl;
}
VOID Produce() {
produceId++;
buf[in++] = produceId;
std::cout << "我是生产者,我生产了:" << produceId << std::endl;
printbuf();
in %= BUFSIZE;
}
VOID Consume() {
consumeId = buf[out];
std::cout << "我是消费者,我消费了:" << consumeId << std::endl;
buf[out++] = 0;
printbuf();
out %= BUFSIZE;
}
DWORD WINAPI Producer(LPVOID) {
while (1) {
P(empty);
P(mutex);
Produce();
Sleep(1000);
V(mutex);
V(full);
}
return 0;
}
DWORD WINAPI Consumer(LPVOID) {
while (1) {
P(full);
P(mutex);
Consume();
Sleep(1000);
V(mutex);
V(empty);
}
return 0;
}
运行效果:
再来看一个复杂一点的生产者 - 消费者问题:
桌子上有一个盘子,每次只能向其中放入一个水果。爸爸专向盘子中放苹果,妈妈专向盘子中放橘子,儿子专等吃盘子中的橘子,女儿专等吃盘子中的苹果。只有盘子为空时, 爸爸或妈妈才可向盘子中放一个水果;仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取岀。
代码:
#include <Windows.h>
#include <iostream>
#include <stdlib.h>
typedef HANDLE Semaphore;
#define P(S) WaitForSingleObject(S, INFINITE)
#define V(S) ReleaseSemaphore(S, 1, NULL)
#define _NULL 0
#define _APPLE 1
#define _ORANGE 2
#define _FATHER 1
#define _MOTHER 2
#define _SON 3
#define _DAUGHTER 4
int what = 0;
int who = 0;
Semaphore apple = CreateSemaphore(
NULL,
0,
1,
NULL
);
Semaphore orange = CreateSemaphore(
NULL,
0,
1,
NULL
);
Semaphore plate = CreateSemaphore(
NULL,
1,
1,
NULL
);
DWORD WINAPI Father(LPVOID);
DWORD WINAPI Mother(LPVOID);
DWORD WINAPI Son(LPVOID);
DWORD WINAPI Daughter(LPVOID);
VOID Put(int);
VOID Get();
VOID PrintPlate();
int main()
{
HANDLE father, mother, son, daughter;;
father = CreateThread(
NULL,
0,
Father,
NULL,
0,
NULL
);
mother = CreateThread(
NULL,
0,
Mother,
NULL,
0,
NULL
);
son = CreateThread(
NULL,
0,
Son,
NULL,
0,
NULL
);
daughter = CreateThread(
NULL,
0,
Daughter,
NULL,
0,
NULL
);
while (1)
{
WaitForSingleObject(father, INFINITE);
WaitForSingleObject(mother, INFINITE);
WaitForSingleObject(son, INFINITE);
WaitForSingleObject(daughter, INFINITE);
}
return 0;
}
VOID PrintPlate() {
std::string _who[4] = {
"爸爸",
"妈妈",
"儿子",
"女儿"
};
std::string _what[2] = {
"苹果",
"橘子"
};
if (who == _FATHER || who == _MOTHER) {
std::cout << "我是:" << _who[who - 1].c_str()
<< "; 我放了【" << _what[what - 1].c_str() << "】在盘子里...."
<< std::endl;
}
else {
std::cout << "我是:" << _who[who - 1].c_str()
<< "; 我从盘子里把【" << _what[what - 1].c_str() << "】拿走了...."
<< std::endl;
}
}
VOID Put(int id) {
what = (id == _APPLE) ? _APPLE : _ORANGE;
who = (id == _FATHER) ? _FATHER : _MOTHER;
PrintPlate();
}
VOID Get() {
who = (what == _APPLE) ? _DAUGHTER : _SON;
PrintPlate();
what = _NULL;
}
DWORD WINAPI Father(LPVOID) {
while (1) {
P(plate);
Put(_APPLE);
Sleep(1000);
V(apple);
}
return 0;
}
DWORD WINAPI Mother(LPVOID) {
while (1) {
P(plate);
Put(_ORANGE);
Sleep(1000);
V(orange);
}
return 0;
}
DWORD WINAPI Son(LPVOID) {
while (1) {
P(orange);
Get();
Sleep(1000);
V(plate);
}
return 0;
}
DWORD WINAPI Daughter(LPVOID) {
while (1) {
P(apple);
Get();
Sleep(1000);
V(plate);
}
return 0;
}
运行效果:
二、读者 - 写者问题
问题描述:
有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:①允许多个读者可以同时对文件执行读操作;②只允许一个写者往文件中写信息;③任一写者在完成写操作之前不允许其他读者或写者工作;④写者执行写操作前,应让已有的读者和写者全部退出。
读优先(读优先可能会导致写者线程饿死)的代码:
#include <Windows.h>
#include <iostream>
#include <stdlib.h>
typedef HANDLE Semaphore;
#define P(S) WaitForSingleObject(S, INFINITE)
#define V(S) ReleaseSemaphore(S, 1, NULL)
int count = 0;
Semaphore mutex = CreateSemaphore(
NULL,
1,
1,
NULL
);
Semaphore rw = CreateSemaphore(
NULL,
1,
1,
NULL
);
DWORD WINAPI Reader(LPVOID);
DWORD WINAPI Writer(LPVOID);
VOID Read();
VOID Write();
int main()
{
HANDLE reader[5];
HANDLE writer[5];
for (int i = 0; i < 5; i++) {
reader[i] = CreateThread(
NULL,
0,
Reader,
NULL,
0,
NULL
);
}
for (int i = 0; i < 5; i++) {
writer[i] = CreateThread(
NULL,
0,
Writer,
NULL,
0,
NULL
);
}
while (1)
{
for (int i = 0; i < 20; i++)
WaitForSingleObject(reader[i], INFINITE);
for (int i = 0; i < 5; i++)
WaitForSingleObject(writer[i], INFINITE);
}
return 0;
}
VOID Read() {
std::cout << "我是读线程,我正在读......." << std::endl;
}
VOID Write() {
std::cout << "我是写线程,我正在写---------------" << std::endl;
}
DWORD WINAPI Reader(LPVOID) {
while (1) {
P(mutex);
if (count == 0)
P(rw);
count++;
Sleep(1000);
V(mutex);
Read();
P(mutex);
count--;
if (count == 0)
V(rw);
V(mutex);
}
return 0;
}
DWORD WINAPI Writer(LPVOID) {
while (1) {
P(rw);
Write();
Sleep(300);
V(rw);
}
return 0;
}
运行效果:
注:可以看到,由于读者线程优先,导致了写者线程饿死
写优先,或者叫读写平衡的代码:
#include <Windows.h>
#include <iostream>
#include <stdlib.h>
typedef HANDLE Semaphore;
#define P(S) WaitForSingleObject(S, INFINITE)
#define V(S) ReleaseSemaphore(S, 1, NULL)
int count = 0;
Semaphore mutex = CreateSemaphore(
NULL,
1,
1,
NULL
);
Semaphore rw = CreateSemaphore(
NULL,
1,
1,
NULL
);
Semaphore w = CreateSemaphore(
NULL,
1,
1,
NULL
);
DWORD WINAPI Reader(LPVOID);
DWORD WINAPI Writer(LPVOID);
VOID Read();
VOID Write();
int main()
{
HANDLE reader[5];
HANDLE writer[5];
for (int i = 0; i < 5; i++) {
reader[i] = CreateThread(
NULL,
0,
Reader,
NULL,
0,
NULL
);
}
for (int i = 0; i < 5; i++) {
writer[i] = CreateThread(
NULL,
0,
Writer,
NULL,
0,
NULL
);
}
while (1)
{
for (int i = 0; i < 20; i++)
WaitForSingleObject(reader[i], INFINITE);
for (int i = 0; i < 5; i++)
WaitForSingleObject(writer[i], INFINITE);
}
return 0;
}
VOID Read() {
std::cout << "我是读线程,我正在读......." << std::endl;
}
VOID Write() {
std::cout << "我是写线程,我正在写---------------" << std::endl;
}
DWORD WINAPI Reader(LPVOID) {
while (1) {
P(w);
P(mutex);
if (count == 0)
P(rw);
count++;
Sleep(1000);
V(mutex);
V(w);
Read();
P(mutex);
count--;
if (count == 0)
V(rw);
V(mutex);
}
return 0;
}
DWORD WINAPI Writer(LPVOID) {
while (1) {
P(w);
P(rw);
Write();
Sleep(300);
V(rw);
V(w);
}
return 0;
}
运行效果:
注:可以看到写者线程被调度了
三、哲学家进餐问题
问题描述:
一张圆桌边上坐着5名哲学家,每两名哲学家之间的桌上摆一根筷子,两根筷子中间是一碗米饭,如图2.12所示。哲学家们倾注毕生精力用于思考和进餐,哲学家在思考时,并不影响他人。只有当哲学家饥饿时,才试图拿起左、右两根筷子(一根一根地拿起)。若筷子已在他人手上,则需要等待。饥饿的哲学家只有同时拿到了两根筷子才可以开始进餐,进餐完毕后,放下筷子继续思考。
代码:
#include <Windows.h>
#include <iostream>
#include <stdlib.h>
typedef HANDLE Semaphore;
#define P(S) WaitForSingleObject(S, INFINITE)
#define V(S) ReleaseSemaphore(S, 1, NULL)
Semaphore chopstick[5];
Semaphore mutex = CreateSemaphore(
NULL,
1,
1,
NULL
);
DWORD WINAPI Philosopher(LPVOID);
VOID InitSemaphore();
VOID Eat(int);
VOID Think(int);
int main()
{
InitSemaphore();
HANDLE philosopher[5];
int id[5];
for (int i = 0; i < 5; i++)
id[i] = i;
for (int i = 0; i < 5; i++) {
philosopher[i] = CreateThread(
NULL,
0,
Philosopher,
(LPVOID)&(id[i]),
0,
NULL
);
}
while (1)
{
for (int i = 0; i < 5; i++)
WaitForSingleObject(philosopher[i], INFINITE);
}
return 0;
}
VOID InitSemaphore() {
for (int i = 0; i < 5; i++) {
chopstick[i] = CreateSemaphore(
NULL,
1,
1,
NULL
);
}
}
VOID Eat(int i) {
std::cout << "哲学家【" << i + 1 << "】正在进餐..." << std::endl;
}
VOID Think(int i) {
std::cout << "哲学家【" << i + 1 << "】正在思考........" << std::endl;
}
DWORD WINAPI Philosopher(LPVOID i) {
while (1) {
P(mutex);
P(chopstick[*((int *)i)]);
P(chopstick[((*((int *)i)) + 1) % 5]);
V(mutex);
Eat(*(int *)i);
Sleep(1000);
V(chopstick[*((int *)i)]);
V(chopstick[((*((int *)i) + 1)) % 5]);
Think(*(int *)i);
}
return 0;
}
运行效果:
注:以上思考的输出出现混乱的原因:
在一个哲学家线程调用到 Think 函数的时候由于没有信号量的保护,因此可能发生竟态条件,由于线程异步地执行,可能在某个线程运行 Think 的时候发生了调度。
四、吸烟者问题
问题描述:
假设一个系统有三个抽烟者进程和一个供应者进程。每个抽烟者不停地卷烟并抽掉它,但要卷起并抽掉一支烟,抽烟者需要有三种材料:烟草、纸和胶水。三个抽烟者中,第一个拥有烟草,第二个拥有纸,第三个拥有胶水。供应者进程无限地提供三种材料,供应者每次将两种材料放到桌子上,拥有剩下那种材料的抽烟者卷一根烟并抽掉它,并给供应者一个信号告诉已完成,此时供应者就会将另外两种材料放到桌上,如此重复(让三个抽烟者轮流地抽烟)。
代码:
#include <Windows.h>
#include <iostream>
#include <stdlib.h>
typedef HANDLE Semaphore;
#define P(S) WaitForSingleObject(S, INFINITE)
#define V(S) ReleaseSemaphore(S, 1, NULL)
#define YanCaoAndZhi 1
#define YanCaoAndJiaoShui 2
#define ZhiAndJiaoShui 3
int num;
int what;
Semaphore offerYanCaoAndZhi = CreateSemaphore(
NULL,
0,
1,
NULL
);
Semaphore offerYanCaoAndJiaoShui = CreateSemaphore(
NULL,
0,
1,
NULL
);
Semaphore offerZhiAndJiaoShui = CreateSemaphore(
NULL,
0,
1,
NULL
);
Semaphore finish = CreateSemaphore(
NULL,
0,
1,
NULL
);
DWORD WINAPI Producer(LPVOID);
DWORD WINAPI Smoker1(LPVOID);
DWORD WINAPI Smoker2(LPVOID);
DWORD WINAPI Smoker3(LPVOID);
VOID Put(int);
VOID Smoke();
int main()
{
HANDLE producer;
HANDLE smoker1, smoker2, smoker3;
producer = CreateThread(
NULL,
0,
Producer,
NULL,
0,
NULL
);
smoker1 = CreateThread(
NULL,
0,
Smoker1,
NULL,
0,
NULL
);
smoker2 = CreateThread(
NULL,
0,
Smoker2,
NULL,
0,
NULL
);
smoker3 = CreateThread(
NULL,
0,
Smoker3,
NULL,
0,
NULL
);
while (1)
{
WaitForSingleObject(producer, INFINITE);
WaitForSingleObject(smoker1, INFINITE);
WaitForSingleObject(smoker2, INFINITE);
WaitForSingleObject(smoker3, INFINITE);
}
return 0;
}
VOID Put(int i) {
if (i == YanCaoAndZhi) {
what = YanCaoAndZhi;
std::cout << "我是供应者,我现在要把【烟草】和【纸】放到桌上" << std::endl;
}
else if (i == YanCaoAndJiaoShui) {
what = YanCaoAndJiaoShui;
std::cout << "我是供应者,我现在要把【烟草】和【胶水】放到桌上" << std::endl;
}
else {
what = ZhiAndJiaoShui;
std::cout << "我是供应者,我现在要把【纸】和【胶水】放到桌上" << std::endl;
}
}
VOID Smoke() {
if (what == YanCaoAndZhi) {
std::cout << "我是吸烟者【3】号,我拥有【胶水】,我现在从桌上拿走【烟草】和【纸】,我开始吸烟了"
<< std::endl;
}
else if (what == YanCaoAndJiaoShui) {
std::cout << "我是吸烟者【2】号,我拥有【纸】,我现在从桌上拿走【烟草】和【胶水】,我开始吸烟了"
<< std::endl;
}
else {
std::cout << "我是吸烟者【1】号,我拥有【烟草】,我现在从桌上拿走【纸】和【胶水】,我开始吸烟了"
<< std::endl;
}
what = 0;
}
DWORD WINAPI Producer(LPVOID) {
while (1) {
num++;
num = num % 3;
if (num == 0) {
Put(YanCaoAndZhi);
V(offerYanCaoAndZhi);
}
else if (num == 1) {
Put(YanCaoAndJiaoShui);
V(offerYanCaoAndJiaoShui);
}
else {
Put(ZhiAndJiaoShui);
V(offerZhiAndJiaoShui);
}
Sleep(1000);
P(finish);
}
return 0;
}
DWORD WINAPI Smoker1(LPVOID){
while (1) {
P(offerZhiAndJiaoShui);
Smoke();
Sleep(1000);
V(finish);
}
return 0;
}
DWORD WINAPI Smoker2(LPVOID) {
while (1) {
P(offerYanCaoAndJiaoShui);
Smoke();
Sleep(1000);
V(finish);
}
return 0;
}
DWORD WINAPI Smoker3(LPVOID) {
while (1) {
P(offerYanCaoAndZhi);
Smoke();
Sleep(1000);
V(finish);
}
return 0;
}
运行效果:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)