进程同步-经典同步问题

进程同步-经典同步问题

 

 

进程同步-经典同步问题
#include <cstdlib>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

static const int kItemRepositorySize = 10; // Item buffer size.
static const int kItemsToProduce = 1000;   // How many items we plan to produce.
std::mutex mutex;


//单生产者--单消费者
namespace SS
{
    struct ItemRepository
    {
        // 产品缓冲区, 配合 read_position 和 write_position 模型环形队列.
        int item_buffer[kItemRepositorySize]; 
        // 消费者读取产品位置.
        size_t read_position; 
        // 生产者写入产品位置.
        size_t write_position;
        // 互斥量,保护产品缓冲区(同一时间只能被生产者或消费者使用)
        std::mutex mtx; 
        // 条件变量, 指示产品缓冲区不为满.
        std::condition_variable repo_not_full; 
        // 条件变量, 指示产品缓冲区不为空.
        std::condition_variable repo_not_empty; 
    } gItemRepository; // 产品库全局变量, 生产者和消费者操作该变量.

    typedef struct ItemRepository ItemRepository;

    //生产者
    void ProduceItem(ItemRepository * ir, int item)
    {
        std::unique_lock<std::mutex> lock(ir->mtx);
        //判断缓存区是否已满
        while (((ir->write_position + 1) % kItemRepositorySize)
            == ir->read_position)
        { //缓存区满的时候,生产者需要等待缓存区不为满的时候才能继续生成,挂起等待
            {
                std::lock_guard<std::mutex> lock(mutex);
                std::cout << "缓冲区满,等待缓冲区不满\n";
            }
            (ir->repo_not_full).wait(lock); // 生产者等待"产品库缓冲区不为满"这一条件发生.
        }

        (ir->item_buffer)[ir->write_position] = item; // 写入产品.
        (ir->write_position)++; // 写入位置后移.

        // 写入位置若是在队列最后则重新设置为初始位置.
        if (ir->write_position == kItemRepositorySize) 
            ir->write_position = 0;

        (ir->repo_not_empty).notify_all(); // 通知消费者产品库不为空.
    }

    //消费者
    int ConsumeItem(ItemRepository *ir)
    {
        int data;
        std::unique_lock<std::mutex> lock(ir->mtx);
        // item buffer is empty, just wait here.
        while (ir->write_position == ir->read_position)
        {
            {
                std::lock_guard<std::mutex> lock(mutex);
                std::cout << "缓冲区空,等待生产者生成产品\n";
            }
            (ir->repo_not_empty).wait(lock); // 消费者等待"产品库缓冲区不为空"这一条件发生.
        }

        data = (ir->item_buffer)[ir->read_position]; // 读取某一产品
        (ir->read_position)++; // 读取位置后移

        if (ir->read_position >= kItemRepositorySize) // 读取位置若移到最后,则重新置位.
            ir->read_position = 0;

        (ir->repo_not_full).notify_all(); // 通知消费者产品库不为满.

        return data; // 返回产品.
    }

    // 生产者任务
    void ProducerTask() 
    {
        for (int i = 1; i <= kItemsToProduce; ++i)
        {
            // sleep(1);
            ProduceItem(&gItemRepository, i); // 循环生产 kItemsToProduce 个产品.

            {
                std::lock_guard<std::mutex> lock(mutex);
                std::cout << "生产第 " << i << "个产品" << std::endl;
            }
        }
    }

    // 消费者任务
    void ConsumerTask() 
    {
        static int cnt = 0;
        while (1)
        {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            int item = ConsumeItem(&gItemRepository); // 消费一个产品.
            {
                std::lock_guard<std::mutex> lock(mutex);
                std::cout << "消费第" << item << "个产品" << std::endl;
            }
            // 如果产品消费个数为 kItemsToProduce, 则退出.
            if (++cnt == kItemsToProduce) break; 
        }
    }

    //初始化开始条件
    void InitItemRepository(ItemRepository *ir)
    {
        ir->write_position = 0; // 初始化产品写入位置.
        ir->read_position = 0; // 初始化产品读取位置.
    }

    void test()
    {
        InitItemRepository(&gItemRepository);

        //新建多个生产者或消费者线程实现多产/多消
        std::thread producer(ProducerTask); // 创建生产者线程.
        std::thread consumer(ConsumerTask); // 创建消费之线程.

        producer.join();
        consumer.join();
        //互斥变量的使用,实现生产者和消费者的循环使用
    }
}

//单生产者-多消费者

int main()
{

    SS::test();
    return 0;
}
单产单消

进程同步-经典同步问题

 

上一篇:RISC CPU设计


下一篇:软件分析课笔记——中间表示