zoukankan      html  css  js  c++  java
  • 【Windows】用信号量实现生产者-消费者模型

    线程并发的生产者-消费者模型:

    1.两个进程对同一个内存资源进行操作,一个是生产者,一个是消费者。

    2.生产者往共享内存资源填充数据,如果区域满,则等待消费者消费数据。

    3.消费者从共享内存资源取数据,如果区域空,则等待生产者填充数据。

    4.生产者的填充数据行为和消费者的消费数据行为不可在同一时间发生。

     

    下面用Windows的信号量以及线程等API模拟生产者-消费者模型

    #include <Windows.h>
    #include <stdio.h>
    #define N 100
    #define TRUE 1
    typedef int Semaphore;
    Semaphore full = 0, Empty = N;            //共享资源区满槽数目和空槽数目
    int in = 0, out = 0;                      //缓冲区生产,消费数据指针
    HANDLE mutex;
    int ProducerThread[5];
    int ConsumerThread[5];
    int Buffer[N+4];                          //缓冲区
    
    int produce_item() {                      //生产(随机数)
        return (rand()%N + N)%N;
    }
    
    int insert_item(int item) {               //插入资源
        in %= N;
        printf("生产到缓冲区槽: %d
    ",in);
        Buffer[in] = item;
        return Buffer[in++];
    }
    
    int remove_item() {                        //移出资源
        out %= N;
        printf("                       取走缓冲区槽 %d 的数
    ",out);
        return Buffer[out++];
    }
    
    int consume_item(int item) {
        //consume it
    }
    
    void down(HANDLE handle) {                  //wait / P
        WaitForSingleObject(handle, INFINITE);
    }
    
    void up(HANDLE handle) {                    //signal / V
        ReleaseSemaphore(handle, 1, NULL);
    }
    
    DWORD WINAPI producer(LPVOID v) {
    
        int item;
    
        while(TRUE) {
    
            item = produce_item();
            if(Empty > 0) {           //down(empty)
                Empty--;
                down(mutex);          //down(mutex)
                insert_item(item);
                full++;               //up(full)
                up(mutex);            //up(mutex)
            }
    
            Sleep(2000);
        }
        return 1;
    }
    
    DWORD WINAPI consumer(LPVOID v) {
    
        int item;
    
        while(TRUE) {
    
            if(full > 0) {             //down(full)
                full--;
                down(mutex);           //down(mutex)
                item = remove_item();
                consume_item(item);
                Empty++;               //up(empty)
                up(mutex);             //up(mutex)
            }
    
            Sleep(2000);
        }
        return 1;
    }
    
    int main()
    {
        DWORD Tid;
    
        mutex = CreateSemaphore(             //创建互斥信号量mutex
                NULL,
                1,
                1,
                NULL
            );
    
        for(int i=0;i<4;i++) {
            ProducerThread[i] = i+1;
            CreateThread(                    //创建生产者线程
                NULL,                        //不能被子线程继承
                0,                           //默认堆栈大小
                producer,                    //生产者函数
                &ProducerThread[i],          //传参
                0,                           //创建后立即执行
                &Tid                         //线程ID
            );
            ConsumerThread[i] = i+1;
            CreateThread(NULL,0,consumer,&ConsumerThread[i],0,&Tid);   //创建消费者线程
        }
    
        Sleep(20000);
        return 0;
    }

    运行结果:

    或者使用自定义的信号量mutex来实现:

    #include <Windows.h>
    #include <stdio.h>
    #define N 100
    #define TRUE 1
    typedef int Semaphore;
    Semaphore mutex = 1;           //互斥信号量
    Semaphore full = 0, Empty = N; //临界区满槽数目和空槽数目
    int in = 0, out = 0;           //缓冲区生产,消费数据指针
    int ProducerThread[5];
    int ConsumerThread[5];
    int Buffer[N+4];               //缓冲区
    
    int produce_item() {           //生产随机数
        return (rand()%N + N)%N;
    }
    
    int insert_item(int item) {    //插入临界区
        in %= N;
        printf("生产到缓冲区槽: %d
    ",in);
        Buffer[in] = item;
        return Buffer[in++];
    }
    
    int remove_item() {            //移出临界区
        out %= N;
        printf("                        取走缓冲区槽 %d 的数
    ",out);
        return Buffer[out++];
    }
    
    int consume_item(int item) {
        //consume it
    }
    
    DWORD WINAPI producer(LPVOID v) {
    
        int item;
    
        while(TRUE) {
    
            item = produce_item();     //生产物品
            Empty--;                   //P(Empty)
            if(Empty < 0)              //没有空槽可以添加数据
                Empty++;               //还原Empty,继续循环等待
            else if(mutex > 0) {       //否则如果mutex = 1,临界区未被访问
                mutex--;               //加锁
                insert_item(item);     //往临界区填入数据
                full++;                //满槽数加1
                mutex++;               //释放锁
            }
            Sleep(2000);
        }
        return 1;
    }
    
    DWORD WINAPI consumer(LPVOID v) {
    
        int item;
    
        while(TRUE) {
    
            full--;                   //P(full)
            if(full < 0)              //如果没有满槽,无法消费
                full++;               //还原full,继续等待
            else if(mutex > 0) {      //否则如果mutex = 1,临界区未被访问
                mutex--;              //加锁
                item = remove_item(); //将数据移出临界区
                consume_item(item);   //消费
                Empty++;              //空槽数目加1
                mutex++;              //释放锁
            }
    
            Sleep(2000);
        }
        return 1;
    }
    
    int main()
    {
        DWORD Tid;
    
        for(int i=0;i<4;i++) {
            ProducerThread[i] = i+1;
            CreateThread(NULL,0,producer,0,0,&Tid);
            ConsumerThread[i] = i+1;
            CreateThread(NULL,0,consumer,0,0,&Tid);
        }
    
        Sleep(20000);
        return 0;
    }

    也能达到效果:

  • 相关阅读:
    七月在线爬虫班学习笔记(五)——scrapy spider的几种爬取方式
    七月在线爬虫班学习笔记(四)——相关库使用与登录问题
    七月在线爬虫班学习笔记(三)——爬虫基础知识与简易爬虫实现
    文件处理工具类
    执行脚本工具类
    LRU
    springboot 整合 memcached
    转载连接
    SpringBoot2.x中redis使用(lettuce)
    Redis 数据类型
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4419979.html
Copyright © 2011-2022 走看看