多线程 冰淇淋店问题的实现

【问题描述】
在一个冰淇淋店中 主要有老板,店员,收银员,以及顾客四个角色。用多线程来模拟他们之间的交互关系。
主要流程:
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:离店。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值