概况

操作系统的实验,大概要求是这样:
问题描述
银行有n个柜员负责为顾客服务,顾客进入银行先取一个号码,然后等着叫号。当某个柜员空闲下来,就叫下一个号。
编程实现该问题,用P、V操作实现柜员和顾客的同步。
不是很难,稍微用点锁、信号量和共享内存

实现要求

1.某个号码只能由一名顾客取得;
2.不能有多于一个柜员叫同一个号;
3.有顾客的时候,柜员才叫号;
4.无柜员空闲的时候,顾客需要等待;
5.无顾客的时候,柜员需要等待。

实现提示

1.互斥对象:顾客拿号,柜员叫号;
2.同步对象:顾客和柜员;
3.等待同步对象的队列:等待的顾客,等待的柜员;
4.所有数据结构在访问时也需要互斥

编译环境

dev c++ x86

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<ctime>
#include<queue>
#include<fstream>
#include<iostream>
#include<stack>
#include<vector>
#include<bitset>
#include<set>
#include<map>
#include<windows.h>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define clr(a,x) memset(a,x,sizeof(a))
#define inf (0x7fffffff)
typedef long long ll;
using namespace std;
// 参数 
#define n (2) // 柜员数量
#define maxm (40) //  最多顾客数
#define maxtime (400) // 最长模拟时间 
#define T (10) // 模拟时sleep的时间,ms为单位 
#define BUFF_SIZE (4+maxm*sizeof(customer)) // 共享内存的大小 
// 柜员队列结构体
struct resource_queue{
    int*head,*tail;
    int Q[n+1];
    resource_queue(){
        head = Q;
        tail = Q;
    }
    void push(int x){
        if(available() == maxm){
            puts("Queue Full!");
            return;
        }
        (*(tail++)) = x;
        if(tail - Q >= maxm + 1)
            tail = Q;
    }
    int front(){
        if(head == tail) return -1;
        return (*head);
    }
    int available(){
        int ans = tail - head;
        return (ans >= 0)?ans : maxm + 1 + ans;
    }
    void pop(){
        if(head == tail){
            puts("Queue Empty!");
            return;
        }
        head++;
        if(head - Q >= maxm + 1)
            head = Q;
    }
}; 
// 顾客信息 
struct customer{
    int come_num,arrive_time,cost_time;// 输入 
    int service_num,service_time,leave_time;// 输出 
    customer():come_num(-1),arrive_time(-1),cost_time(-1),service_num(-1),
    service_time(-1),leave_time(-1){}
    void print(){
        printf("customer_id == %d , arrive_time == %d , cost_time == %d , ",come_num,arrive_time,cost_time);
        printf("service_num == %d , service_time == %d , leave_time == %d\n",service_num,service_time,leave_time);
    }
};
// 线程传递参数的结构体
struct info{
    customer*x; // 当前顾客信息 
    int*pBuff; // 共享内存指针 
    resource_queue*pQue; // 队列内存指针 
    HANDLE resource_count; // 信号量 
    HANDLE resource_mutex; // 资源队列的互斥锁 
}; 
// 处理顾客的函数
void process_customer(LPVOID Notype_pPara){
    info*p = (info*)Notype_pPara; // 转换为我们需要的info*
    customer*x = p->x;
    int*pBuff = p->pBuff;
    resource_queue*que = p->pQue;
    HANDLE resource_count = p->resource_count; 
    HANDLE resource_mutex = p->resource_mutex; 
    for(;;){// 循环等待 
        if(x->service_time == -1 && (*pBuff) >= x->arrive_time){// 避免重复开始 
            WaitForSingleObject(resource_count, INFINITE);// 等待柜员空闲,P操作
            WaitForSingleObject(resource_mutex, INFINITE);// 等待对队列进行操作 
            x->service_num = que->front();
            que->pop();
            x->service_time = (*pBuff);
            x->leave_time = x->service_time + x->cost_time;
            ReleaseMutex(resource_mutex);// 释放队列资源 
        }
        if((*pBuff) == x->leave_time){
            WaitForSingleObject(resource_mutex, INFINITE);// 等待对队列进行操作 
            que->push(x->service_num);
            x->print();
            ReleaseMutex(resource_mutex);// 释放队列资源 
            ReleaseSemaphore(resource_count,1,NULL);// 释放柜员,V操作
            break;
        }
        Sleep(T*0.3);// 防止原地等待消耗太多资源,相当于每隔0.3*T进行判断,这样也可以保证不会错过时间的变化 
    }
}
int main(){    
    // 创建共享文件句柄
    HANDLE hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE,    // 物理文件句柄
        NULL,                    // 默认安全级别
        PAGE_READWRITE,          // 读写权限 
        0,                       // 文件映射的最大长度的高32位
        BUFF_SIZE,               // 文件映射的最大长度的低32位
        "buff"                  // 共享内存名称
        );
    // 内存读取指针 
    int*pBuff = (int*)MapViewOfFile(// 返回的是char*,转换成我们需要的int* 
        hMapFile,                // 共享文件的句柄 
        FILE_MAP_ALL_ACCESS,     // 读写权限 
        0,                         // 文件映射起始偏移的高32位
        0,                       // 文件映射起始偏移的低32位
        BUFF_SIZE                // 共享内存大小 
        );
    // 创建共享文件句柄
    HANDLE hQueFile = CreateFileMapping(
        INVALID_HANDLE_VALUE,    // 物理文件句柄
        NULL,                    // 默认安全级别
        PAGE_READWRITE,          // 读写权限 
        0,                       // 文件映射的最大长度的高32位
        BUFF_SIZE,               // 文件映射的最大长度的低32位
        "queue"                  // 共享内存名称
        );
    // 内存读取指针 
    resource_queue*pQue = (resource_queue*)MapViewOfFile(// 返回的是char*,转换成我们需要的resource_queue
        hQueFile,                // 共享文件的句柄 
        FILE_MAP_ALL_ACCESS,     // 读写权限 
        0,                         // 文件映射起始偏移的高32位
        0,                       // 文件映射起始偏移的低32位
        sizeof(resource_queue)   // 共享内存大小 
        );
    (*pBuff) = 0; // 第一位表示当前时间 
    customer*x = (customer*)(pBuff + 1); // 后面部分为顾客信息 
    customer tmp_x[maxm];
    memcpy(x,&tmp_x,maxm*sizeof(customer));
    resource_queue tmp_que; // que共享内存为资源队列
    memcpy(pQue,&tmp_que,sizeof(resource_queue));
    
    // 初始化资源队列
    for(int i = 0; i < n; i ++)
        pQue->push(i);

    // 创建互斥锁控制资源队列的访问与修改 
    HANDLE resource_mutex = CreateMutex(
         NULL,               // 互斥锁安全参数 
         FALSE,              // 互斥锁初始值 
        "resource_mutex"    // 互斥锁的名称 
        ); 
            
    // 创建信号量记录当前柜员数量 
    HANDLE resource_count = CreateSemaphore(
         NULL,               // 信号量安全参数 
         n,                  // 信号量初始值 
         n,                  // 信号量最大值 
        "resource_count"    // 信号量的名称 
        ); 
    
    // 读入顾客信息 
    info Para[maxm];
    int m = 0; // 顾客数量
    HANDLE thread[maxm];// 每个顾客对应一个线程 
    ifstream fin("#test.in",ios::in); // 用ifstream方便判断文件结尾 
    while(!fin.eof()){
        fin >> x[m].come_num >> x[m].arrive_time >> x[m].cost_time;
        Para[m].x = x + m;
        Para[m].pBuff = pBuff;
        Para[m].pQue = pQue;
        Para[m].resource_count = resource_count;
        Para[m].resource_mutex = resource_mutex;
        thread[m] = CreateThread(// 为每个顾客创建一个进程 
            NULL,                     // 线程安全相关属性,一般置为NULL 
            0,                       // 初始栈大小 
            (LPTHREAD_START_ROUTINE)process_customer,       // 线程执行函数,需要转换格式 
            (Para + m),              // 传入线程的参数结构体指针 
            0,                       // 线程创建属性,0即创建后马上激活 
            NULL                     // 是否返回线程ID,NULL不返回 
            );
        m++;
    }
    
    puts("Init Completed");
    puts("Using Para:");
    printf("n == %d , m = %d , maxtime = %d\n",n,m,maxtime);
    puts("Now Start Simulating:");
    
    // 模拟时间流逝
    // 需要sleep一段时间以让子现成都有机会运行 
    (*pBuff) = -1;
    for(;;){
        WaitForSingleObject(resource_mutex, INFINITE);// 等待对队列进行操作,为了防止输出乱序或者访问出错 
        (*pBuff) ++;
        cout<<"time == "<<(*pBuff)<<endl;
        if((*pBuff) == maxtime) break;    
        ReleaseMutex(resource_mutex);// 释放队列资源 
        Sleep(T);
    }      
    
    // 等待输出结果 
    WaitForMultipleObjects(
        m,                           // 等待对象数量
        thread,                      // 对象数组指针
        TRUE,                        // 等待类型:TRUE等待全部 FALSE等待一个
        INFINITE                     // 等待时间 
    );
    
    // 取消共享内存,关闭句柄 
    UnmapViewOfFile(pBuff);
    CloseHandle(hMapFile);
    CloseHandle(hQueFile);
    CloseHandle(resource_count);
    CloseHandle(resource_mutex);
    
    fclose(stdin);
    //fclose(stdout);
    return 0;
}
Last modification:June 8th, 2020 at 12:17 am
如果觉得我的文章对你有用,请随意赞赏