生产者/消费者问题

在模块化编程中,高内聚和低耦合通常是我们要达到的标准,相信对于生产者消费者就是一个这样的问题。

在对线程的学习中,看了一下这个实例,因此在这里学习一下。

生产者和消费者问题是一个经典的线程同步的问题,在实际生活中我们很容易遇到,也称为有限缓冲区问题,生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者

上面是百度百科对于这个问题的解释,而对于我自己的理解呢,就是一个线程往缓冲区里面写东西,另一个线程从缓冲区里面读东西,当缓冲区满的时候,我不再写,此时写线程进入休眠,等待缓冲区非满的信号过来,我们再进行写,当缓冲区空的时候,我们的读线程就进入休眠,等待缓冲区非空的信号过来,我们再进行读,因为线程同步的问题,因此,存在着多个读写线程的竞争,也就是这些线程进行着互斥访问,而且读写的速度也不一样,因此需要我们的互斥锁来锁定多线程,让线程一个一个执行

那么问题来了,一个简单的读写操作为什么要搞这么多东东呢?

  1. 解耦
    假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。

  2. 生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会白白糟蹋大好时光。
    使用了生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体生产者把制造出来的数据往缓冲区一丢,就可以再去生产下一个数据。基本上不用依赖消费者的处理速度。

3.缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。

对于这些基本的概念,就讲这么多,下面给出思路以及我们的程序:

生产者进程:

1、调用pthread_mutex_lock()对lock上锁,并根据以下条件判断缓冲区是否已满;
(writepos + 1) % BUFSIZE == readpos
2、若满,调用ptread_cond_wait()进入阻塞,等待notfull条件变量;
3、写入数据并移动写指针writepos;
4、调用pthread_cond_signal()向消费者信号通过notempty条件变量;
5、调用pthread_mutex_unlock()对mutex解锁。

消费者进程:

1、调用pthread_mutex_lock()对lock上锁,并根据以下条件判断缓冲区是否为空;
writepos == readpos
2、若空,调用ptread_cond_wait()进入阻塞,等待notempty条件变量;
3、读取数据并移动读指针readpos;
4、调用pthread_cond_signal()向消费者信号通过notfull条件变量;
5、调用pthread_mutex_unlock()对mutex解锁。

线程管理相关函数
int pthread_create( );
int pthread_join();
线程互斥控制相关函数
int pthread_mutex_init();
int pthread_mutex_lock();
int pthread_mutex_unlock();
线程条件变量控制相关函数
int pthread_cond_init();
int pthread_cond_wait();
int pthread_cond_signal()

/*********************************************************************************
 *      Copyright:  (C) 2017 tangyanjun<519656780@qq.com>
 *                  All rights reserved.
 *
 *       Filename:  pro_Cus.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(08/13/2017)
 *         Author:  tangyanjun <519656780@qq.com>
 *      ChangeLog:  1, Release initial version on "08/13/2017 08:35:20 PM"
 *                 
 ********************************************************************************/
#include <stdio.h>
#include <pthread.h>
#define   BUFSIZE   1000
#define   OVER      (-1)

struct producers{
    int buffer[BUFSIZE];
    pthread_mutex_t  lock;   //互斥锁
    int readpos;
    int writepos;
    pthread_cond_t  notempty;  //缓冲区非空条件判断
    pthread_cond_t  notfull;   //缓冲区未满条件判断
};

struct producers buffer;


void init(struct producers *b)
{
    pthread_mutex_init(&b->lock, NULL);
    pthread_cond_init(&b->notempty, NULL);
    pthread_cond_init(&b->notfull, NULL);
    b->readpos = 0;
    b->writepos = 0;
}

void put(struct producers* b, int data)
{
    pthread_mutex_lock(&b->lock); //如果互斥锁mutex已经被上锁则挂起生产者线程,并返回

    if((b->writepos + 1) % BUFSIZE == b->readpos)   //等待缓冲区满
    {
        pthread_cond_wait(&b->notfull, &b->lock);  //缓冲区满,生产者将被挂起,直至重新被唤醒
    }

    b->buffer[b->writepos] = data;  //写数据
    b->writepos++;     //移动指针

    if(b->writepos >= BUFSIZE)
    {
        b->writepos = 0;
    }

    pthread_cond_signal(&b->notempty);  //设置缓冲区非空的条件变量
    pthread_mutex_unlock(&b->lock);
}

int get(struct producers *b)
{
    int data;
    pthread_mutex_lock(&b->lock);

    if(b->writepos == b->readpos)
    {
        pthread_cond_wait(&b->notempty, &b->lock); //等待缓冲区非空
    }

    data = b->buffer[b->readpos];   //读数据
    b->readpos++;      //移动指针

    if(b->readpos >= BUFSIZE)
    {
        b->readpos = 0;
    }

    pthread_cond_signal(&b->notfull);   //设置缓冲区未满的条件变量
    pthread_mutex_unlock(&b->lock);

    return data;
}

void *producer(void *data)
{
    int n;
    for(n = 0; n < 14; n++)
    {
        printf("[%d] ", n);
        put(&buffer, n);
    }
    put(&buffer, OVER);
    return NULL;
}

void *consumer(void *data)
{
    int d;
    while(1)
    {
        d = get(&buffer);
        if(d == OVER)
        {
            break;
        }
        printf("(%d) ", d);
    }
    return NULL;
}

int main()
{
    int i = 0;
    pthread_t th_a, th_b, th_c, th_d;
    void *retval;
    init(&buffer);
    pthread_create(&th_a, NULL, producer, 0);
    pthread_create(&th_b, NULL, consumer, 0);
    pthread_create(&th_a, NULL, producer, 0);
    pthread_create(&th_b, NULL, consumer, 0);

    pthread_join(th_a, &retval);
    pthread_join(th_b, &retval);
    printf("\n");
    return 0;
}

这里写图片描述

根据我们的结果打印可以看出生产者和消费者两个线程的确是在交叉进行,竞争资源。由于时间原因,现阶段没有深入学习,以后再好好深入。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python模拟生产者/消费者问题是一种常见的多线程问题生产者线程负责生成数据并将其放入共享队列中,而消费者线程则负责从队列中取出数据并进行处理。这种设计模式可以有效地解决生产者消费者之间的数据同步和互斥问题。 使用Python可以通过线程和队列模块来实现生产者/消费者模式。线程模块可以创建和管理线程,队列模块可以提供线程安全的队列数据结构。 具体实现可以按照以下步骤进行: 1. 导入所需的模块,包括线程和队列模块。 2. 创建一个共享队列,用于生产者消费者之间的数据传递。 3. 定义一个生产者函数,该函数在一个循环中生成数据并将其放入队列中。 4. 定义一个消费者函数,该函数在一个循环中从队列中取出数据并进行处理。 5. 创建生产者线程消费者线程,并启动它们。 6. 等待线程结束。 以下是一个示例代码来模拟生产者/消费者问题: ```python import threading import queue # 创建共享队列 queue = queue.Queue() # 定义生产者函数 def producer(): while True: data = generate_data() # 生成数据 queue.put(data) # 将数据放入队列中 # 定义消费者函数 def consumer(): while True: data = queue.get() # 从队列中取出数据 process_data(data) # 处理数据 # 创建生产者线程消费者线程 producer_thread = threading.Thread(target=producer) consumer_thread = threading.Thread(target=consumer) # 启动线程 producer_thread.start() consumer_thread.start() # 等待线程结束 producer_thread.join() consumer_thread.join() ``` 以上代码中,生产者函数(producer)在一个循环中生成数据并将其放入队列中,消费者函数(consumer)在一个循环中从队列中取出数据并进行处理。生产者线程消费者线程分别启动后,可以并行执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值