在一个冰淇淋店中 主要有老板,店员,收银员,以及顾客四个角色。用多线程来模拟他们之间的交互关系。
主要流程:
10个顾客到冰淇淋店买冰淇淋,每个顾客需要买1到4个冰淇淋,对每个冰淇淋,指派一名店员来制作。
店里最多有5位店员制作冰淇淋。顾客等候购买数量的冰淇淋制作完成后,到收银台取号,排队,结帐。
店员完成每一个冰淇淋,都要先到老板办公室交给老板审核,如果审核不通过,则重做,审核通过再交给顾客。
交互约束:
1.老板办公室最多只能一个店员进入,不可同时进入两个店员。
2.老板对顾客需求的所有冰淇淋审核完成后才能离开。
3.顾客拿到冰淇淋到收银员那去排队交钱时,必须满足FIFO。
4.只有5位店员可以同时工作。
分析及实现:
主函数:作为老板的角色,安排一天的工作。创建10个顾客线程,并且监视整个生产过程。
顾客线程:创建店员线程,并且模拟产生所需数量的冰淇淋。
店员线程:TotalNeeds个冰淇淋的制作,并且与老板进行交互通信,实现成品的检验。
【PV原语】
(略)
【代码(VC6.0 Console Application)】
#include <stdlib.h>
#include <windows.h>
#include <pthread.h>
#include <semaphore.h>
#pragma comment(lib, "pthreadVC2.lib")
#define NUM_CUSTOM 10 // 设定顾客人数
#define NUM_CLERK 5 // 设定店员人数
void *Clerk(void *clerkDone); // void Clerk(Semosphere clerkDone)
void *Customer(void *numIceCream); // void Customer(int numIceCream)
void *Cashier(void *arg); // void cashier()
void plan(int TotalNeeds);
void progress(bool passed, int numChecked, int numCheckedAndPassed, int TotalNeeds);
void MakeIceCream();
void WalkToCashier(int tid, int numIceCream, int n);
void CashOut(int i);
int IceNum[NUM_CUSTOM]; // 每位顾客购买的数量
pthread_t cuThread[NUM_CUSTOM];
pthread_t maThread;
pthread_t caThread;
sem_t capacity; // (5) 店员
struct //店员用
{
bool passed; // (false) 用于店员得到老板审核结果
sem_t requested; // (0) 用于老板等待店员请求
sem_t finished; // (0) 用于店员等待老板审核完成
sem_t locked; // (1) 用于实现店员对老板办公室的访问互斥
}inspect;
struct //收银员用
{
int number; // (0) 顾客排队号码
sem_t numLock; // (1) number互斥锁
sem_t requested; // (0) 顾客唤醒收银员
sem_t finished[NUM_CUSTOM]; // (0) 通知顾客结账完毕
}line;
int main(int argc, char* argv[])
{
int i, TotalNeeds = 0;
srand(time(0));
sem_init(&capacity, 0, NUM_CLERK); // 店员人数
line.number = 0;
for(i = 0 ; i < NUM_CUSTOM ; i++)
{
TotalNeeds += IceNum[i] = rand()%4 + 1;
pthread_create(&cuThread[i], NULL, Customer, (void *)i); //创建顾客线程并传入顾客顺序号
sem_init(&line.finished[i], 0, 0); //
}
pthread_create(&caThread, NULL, Cashier, (void *)NULL); //创建收银员线程,无参数
int numChecked = 0; //记录老板核查的总数
int numCheckedAndPassed = 0; //记录核查通过的总数
plan((int)TotalNeeds);
inspect.passed = false;
sem_init(&inspect.requested, 0, 0);
sem_init(&inspect.finished, 0, 0);
sem_init(&inspect.locked, 0, 1);
while(numCheckedAndPassed < (int)TotalNeeds) //当合格数未到总需求,继续核查
{
sem_wait(&inspect.requested); //等待核查请求
numChecked++; //核查数加1
inspect.passed = rand()%2 ? true : false; //模拟核查结果
if(inspect.passed) //如果合格,记录
numCheckedAndPassed++;
progress(inspect.passed, numChecked, numCheckedAndPassed, (int)TotalNeeds);
sem_post(&inspect.finished); //完成核查
}
for(i=0; i<NUM_CUSTOM; i++)
pthread_join(cuThread[i], NULL);
pthread_join(maThread, NULL);
pthread_join(caThread, NULL);
return 0;
}
void *Customer(void *index) // void Customer(int numIceCream)
{
pthread_t clThread[4];
sem_t clerkDone[4]; //(0) //建立只有自己才能够识别的信号量
int tid = (int)index;
int numIceCream = IceNum[tid];
printf("顾客%.2d:购买冰淇淋%d个。\n", tid, numIceCream);
sem_init(&line.numLock, 0, 1);
for(int i = 0 ; i < (int)numIceCream ; i++) { //创建店员线程
sem_wait(&capacity);
sem_init(&clerkDone[i], 0, 0);
pthread_create(&clThread[i], NULL, Clerk, (void *)clerkDone[i]);
}
for(i = 0 ; i < (int)numIceCream ; i++) //等待制作完成
sem_wait(&clerkDone[i]);
sem_wait(&line.numLock); //进入临界区,获得排列号
int place = line.number++;
sem_post(&line.numLock);
WalkToCashier(tid, numIceCream, place); //准备结帐
sem_post(&line.requested); //发送请求(这里的requested可以累加)
sem_wait(&line.finished[place]); //等待处理完成
printf("顾客%.2d:离店。\n", tid);
pthread_exit(0);
return NULL;
}
void *Clerk(void *clerkDone) // void Clerk(Semosphere clerkDone)
{
bool passed = false;
while(!passed) //如果没有通过,就一直做
{
MakeIceCream(); //制作过程
sem_wait(&inspect.locked); //等待获得老板办公室权限
sem_post(&inspect.requested); //给老板发送请求
sem_wait(&inspect.finished); //等待老板核查
passed = inspect.passed; //获取检验结果
sem_post(&inspect.locked); //出办公室要关门
}
sem_post((sem_t *)&clerkDone); //将冰淇淋交给顾客
sem_post(&capacity); //招呼下一个顾客
return NULL;
}
void *Cashier(void *arg) // void cashier()
{
sem_init(&line.requested, 0, 0); //
for(int i=0; i<NUM_CUSTOM; i++) //依次处理
{
sem_wait(&line.requested); //等待请求
CashOut(i); //收钱
sem_post(&line.finished[i]); //通知对应顾客
}
return NULL;
}
void plan(int TotalNeeds)
{
printf("老板:计划制作%d个冰淇淋。\n", TotalNeeds);
}
void progress(bool passed, int numChecked, int numCheckedAndPassed, int TotalNeeds)
{
int sval;
char msg[20];
sem_getvalue (&capacity, &sval);
if( sval >= 0 )
sprintf(msg, "%d位员工在工作。", NUM_CLERK - sval);
else
sprintf(msg, "%d位顾客在等待。", -sval);
if(passed)
printf("老板:检查合格。合格率:%2.1f%%, 进度%d/%d, %s\n",
100.0*numCheckedAndPassed/numChecked, numCheckedAndPassed, TotalNeeds, msg);
else
printf("老板:检查不合格。合格率:%2.1f%%, 进度%d/%d, %s\n",
100.0*numCheckedAndPassed/numChecked, numCheckedAndPassed, TotalNeeds, msg);
}
void MakeIceCream()
{
puts("店员:制作冰淇淋...");
Sleep(400);
}
void WalkToCashier(int tid, int numIceCream, int n)
{
printf("顾客%.2d:获得%d个冰淇淋,去收银台取号%d...\n", tid, numIceCream, n);
Sleep(100);
}
void CashOut(int i)
{
printf("收银员:顾客%d货款付讫。\n", i);
Sleep(100);
}
【输出结果】
顾客00:购买冰淇淋2个。
顾客02:购买冰淇淋4个。
顾客04:购买冰淇淋3个。
顾客03:购买冰淇淋3个。
顾客01:购买冰淇淋4个。
顾客07:购买冰淇淋3个。
顾客06:购买冰淇淋3个。
顾客05:购买冰淇淋4个。
店员:制作冰淇淋...
店员:制作冰淇淋...
店员:制作冰淇淋...
老板:计划制作34个冰淇淋。
店员:制作冰淇淋...
顾客08:购买冰淇淋4个。
店员:制作冰淇淋...
顾客09:购买冰淇淋4个。
老板:检查不合格。合格率:0.0%, 进度0/34, 9位顾客在等待。
店员:制作冰淇淋...
老板:检查不合格。合格率:0.0%, 进度0/34, 9位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:33.3%, 进度1/34, 9位顾客在等待。
老板:检查不合格。合格率:25.0%, 进度1/34, 8位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:40.0%, 进度2/34, 8位顾客在等待。
店员:制作冰淇淋...
店员:制作冰淇淋...
老板:检查合格。合格率:50.0%, 进度3/34, 9位顾客在等待。
老板:检查不合格。合格率:42.9%, 进度3/34, 8位顾客在等待。
店员:制作冰淇淋...
老板:检查不合格。合格率:37.5%, 进度3/34, 8位顾客在等待。
店员:制作冰淇淋...
老板:检查不合格。合格率:33.3%, 进度3/34, 8位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:40.0%, 进度4/34, 8位顾客在等待。
店员:制作冰淇淋...
店员:制作冰淇淋...
老板:检查不合格。合格率:36.4%, 进度4/34, 9位顾客在等待。
店员:制作冰淇淋...
老板:检查不合格。合格率:33.3%, 进度4/34, 9位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:38.5%, 进度5/34, 9位顾客在等待。
老板:检查不合格。合格率:35.7%, 进度5/34, 8位顾客在等待。
店员:制作冰淇淋...
老板:检查不合格。合格率:33.3%, 进度5/34, 8位顾客在等待。
店员:制作冰淇淋...
店员:制作冰淇淋...
老板:检查不合格。合格率:31.3%, 进度5/34, 9位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:35.3%, 进度6/34, 9位顾客在等待。
老板:检查合格。合格率:38.9%, 进度7/34, 9位顾客在等待。
顾客00:获得2个冰淇淋,去收银台取号0...
店员:制作冰淇淋...
老板:检查合格。合格率:42.1%, 进度8/34, 9位顾客在等待。
老板:检查合格。合格率:45.0%, 进度9/34, 9位顾客在等待。
店员:制作冰淇淋...
店员:制作冰淇淋...
店员:制作冰淇淋...
收银员:顾客0货款付讫。
顾客00:离店。
老板:检查不合格。合格率:42.9%, 进度9/34, 9位顾客在等待。
店员:制作冰淇淋...
老板:检查不合格。合格率:40.9%, 进度9/34, 9位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:43.5%, 进度10/34, 9位顾客在等待。
老板:检查不合格。合格率:41.7%, 进度10/34, 8位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:44.0%, 进度11/34, 8位顾客在等待。
店员:制作冰淇淋...
店员:制作冰淇淋...
老板:检查不合格。合格率:42.3%, 进度11/34, 9位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:44.4%, 进度12/34, 9位顾客在等待。
老板:检查不合格。合格率:42.9%, 进度12/34, 8位顾客在等待。
店员:制作冰淇淋...
老板:检查不合格。合格率:41.4%, 进度12/34, 8位顾客在等待。
店员:制作冰淇淋...
老板:检查不合格。合格率:40.0%, 进度12/34, 8位顾客在等待。
店员:制作冰淇淋...
店员:制作冰淇淋...
老板:检查合格。合格率:41.9%, 进度13/34, 9位顾客在等待。
老板:检查合格。合格率:43.8%, 进度14/34, 8位顾客在等待。
老板:检查合格。合格率:45.5%, 进度15/34, 9位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:47.1%, 进度16/34, 8位顾客在等待。
老板:检查不合格。合格率:45.7%, 进度16/34, 7位顾客在等待。
店员:制作冰淇淋...
店员:制作冰淇淋...
店员:制作冰淇淋...
店员:制作冰淇淋...
老板:检查合格。合格率:47.2%, 进度17/34, 7位顾客在等待。
老板:检查不合格。合格率:45.9%, 进度17/34, 6位顾客在等待。
店员:制作冰淇淋...
老板:检查不合格。合格率:44.7%, 进度17/34, 6位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:46.2%, 进度18/34, 6位顾客在等待。
顾客04:获得3个冰淇淋,去收银台取号1...
老板:检查不合格。合格率:45.0%, 进度18/34, 6位顾客在等待。
店员:制作冰淇淋...
店员:制作冰淇淋...
店员:制作冰淇淋...
收银员:顾客1货款付讫。
顾客04:离店。
老板:检查合格。合格率:46.3%, 进度19/34, 7位顾客在等待。
老板:检查不合格。合格率:45.2%, 进度19/34, 6位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:46.5%, 进度20/34, 6位顾客在等待。
老板:检查不合格。合格率:45.5%, 进度20/34, 5位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:46.7%, 进度21/34, 6位顾客在等待。
店员:制作冰淇淋...
店员:制作冰淇淋...
店员:制作冰淇淋...
老板:检查合格。合格率:47.8%, 进度22/34, 5位顾客在等待。
老板:检查合格。合格率:48.9%, 进度23/34, 4位顾客在等待。
顾客02:获得4个冰淇淋,去收银台取号2...
店员:制作冰淇淋...
店员:制作冰淇淋...
老板:检查不合格。合格率:47.9%, 进度23/34, 4位顾客在等待。
店员:制作冰淇淋...
老板:检查不合格。合格率:46.9%, 进度23/34, 4位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:48.0%, 进度24/34, 4位顾客在等待。
顾客07:获得3个冰淇淋,去收银台取号3...
店员:制作冰淇淋...
收银员:顾客2货款付讫。
顾客02:离店。
收银员:顾客3货款付讫。
顾客07:离店。
老板:检查不合格。合格率:47.1%, 进度24/34, 4位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:48.1%, 进度25/34, 4位顾客在等待。
顾客06:获得3个冰淇淋,去收银台取号4...
店员:制作冰淇淋...
老板:检查合格。合格率:49.1%, 进度26/34, 4位顾客在等待。
顾客03:获得3个冰淇淋,去收银台取号5...
老板:检查不合格。合格率:48.1%, 进度26/34, 3位顾客在等待。
店员:制作冰淇淋...
老板:检查合格。合格率:49.1%, 进度27/34, 3位顾客在等待。
店员:制作冰淇淋...
店员:制作冰淇淋...
收银员:顾客4货款付讫。
收银员:顾客5货款付讫。
顾客06:离店。
顾客03:离店。
老板:检查合格。合格率:50.0%, 进度28/34, 2位顾客在等待。
老板:检查合格。合格率:50.9%, 进度29/34, 1位顾客在等待。
老板:检查合格。合格率:51.7%, 进度30/34, 1位顾客在等待。
老板:检查合格。合格率:52.5%, 进度31/34, 5位员工在工作。
顾客05:获得4个冰淇淋,去收银台取号6...
老板:检查合格。合格率:53.3%, 进度32/34, 4位员工在工作。
顾客01:获得4个冰淇淋,去收银台取号7...
店员:制作冰淇淋...
店员:制作冰淇淋...
收银员:顾客6货款付讫。
顾客05:离店。
收银员:顾客7货款付讫。
顾客01:离店。
老板:检查不合格。合格率:52.5%, 进度32/34, 2位员工在工作。
店员:制作冰淇淋...
老板:检查合格。合格率:53.2%, 进度33/34, 2位员工在工作。
顾客08:获得4个冰淇淋,去收银台取号8...
收银员:顾客8货款付讫。
顾客08:离店。
老板:检查合格。合格率:54.0%, 进度34/34, 1位员工在工作。
顾客09:获得4个冰淇淋,去收银台取号9...
收银员:顾客9货款付讫。
顾客09:离店。