精华内容
下载资源
问答
  • 此实例在windows 10系统上可以成功运行,可以修改一下,在linux上也可以运行,思路都是一样的。 说明:这个是个图书馆案例,默认100个座位,生产者消费者各2个线程 (修改:加锁
  • // 产品队列 int ready=0; //互斥锁 pthread_mutex_t mutex; //条件变量 pthread_cond_t has_product;...//生产者 void * produce(void *arg){ char* name=(char*)arg; LOGI("生产 %s", name);
    #include <queue>
    #include <pthread.h>
    
    // 产品队列
    int ready=0;
    
    //互斥锁
    pthread_mutex_t  mutex;
    
    //条件变量
    pthread_cond_t has_product;
    
    std::queue<char *> queue1;
    
    //生产者
    
    void * produce(void *arg){
    
        char* name=(char*)arg;
        LOGI("生产 %s", name);
        for(;;){
            //锁住
            pthread_mutex_lock(&mutex);
            ready++;
            queue1.push(name);
            LOGI("生产者  生产 %d \n",ready);
            //发送一条解锁消息
            pthread_cond_signal(&has_product);
            //解锁
            pthread_mutex_unlock(&mutex);
            sleep(3);
        }
    }
    
    //消费者
    void* consumer(void* arg){
        char* name=(char*)arg;
        for(;;){
            pthread_mutex_lock(&mutex);
            //如果产品列表为空   继续等待不可能只有1个消费者
            while(ready==0){
                LOGI("没有产品了");
                pthread_cond_wait(&has_product,&mutex);
            }
            //加锁
            ready--;
            char * result = queue1.front();
            queue1.pop();
            LOGI("消费者 %s  剩余 %s, %d\n",name,result, ready);
            pthread_mutex_unlock(&mutex);
            sleep(1);
        }
    
    }
    void runtest(){
        pthread_mutex_init(&mutex,NULL);
    
        pthread_cond_init(&has_product,NULL);
        //线程的引用
        pthread_t tid1,tid2,tid3;
        char* name = "生产者";
        char* name1 = "消费者1";
        char* name2 = "消费者2";
            pthread_create(&tid1, NULL, produce, name);
    		pthread_create(&tid2,NULL,consumer,name1);
    		pthread_create(&tid3,NULL,consumer,name2);
    
        LOGI("开启线程");
        void *rval;
        pthread_join(tid1,&rval);
        pthread_join(tid2,&rval);
        pthread_join(tid3,&rval);
    
        LOGI("线程结束%d\n",rval);
    
    }



    运行结果:

    11-04 19:44:40.250 11553-11620/com.test.videoplayer I/videoplayer: 生产者  生产 1 
    11-04 19:44:40.250 11553-11621/com.test.videoplayer I/videoplayer: 消费者 消费者1  剩余 生产者, 0
    11-04 19:44:41.250 11553-11621/com.test.videoplayer I/videoplayer: 没有产品了
    11-04 19:44:43.250 11553-11620/com.test.videoplayer I/videoplayer: 生产者  生产 1 
    11-04 19:44:43.250 11553-11622/com.test.videoplayer I/videoplayer: 消费者 消费者2  剩余 生产者, 0
    11-04 19:44:44.250 11553-11622/com.test.videoplayer I/videoplayer: 没有产品了
    11-04 19:44:46.250 11553-11620/com.test.videoplayer I/videoplayer: 生产者  生产 1 
    11-04 19:44:46.250 11553-11621/com.test.videoplayer I/videoplayer: 消费者 消费者1  剩余 生产者, 0
    11-04 19:44:47.250 11553-11621/com.test.videoplayer I/videoplayer: 没有产品了
    11-04 19:44:49.250 11553-11620/com.test.videoplayer I/videoplayer: 生产者  生产 1 
    11-04 19:44:49.250 11553-11622/com.test.videoplayer I/videoplayer: 消费者 消费者2  剩余 生产者, 0
    11-04 19:44:50.250 11553-11622/com.test.videoplayer I/videoplayer: 没有产品了
    11-04 19:44:52.250 11553-11620/com.test.videoplayer I/videoplayer: 生产者  生产 1 
    11-04 19:44:52.250 11553-11621/com.test.videoplayer I/videoplayer: 消费者 消费者1  剩余 生产者, 0
    11-04 19:44:53.250 11553-11621/com.test.videoplayer I/videoplayer: 没有产品了
    11-04 19:44:55.250 11553-11620/com.test.videoplayer I/videoplayer: 生产者  生产 1 
    11-04 19:44:55.250 11553-11622/com.test.videoplayer I/videoplayer: 消费者 消费者2  剩余 生产者, 0
    11-04 19:44:56.250 11553-11622/com.test.videoplayer I/videoplayer: 没有产品了
    11-04 19:44:58.250 11553-11620/com.test.videoplayer I/videoplayer: 生产者  生产 1 
    11-04 19:44:58.250 11553-11621/com.test.videoplayer I/videoplayer: 消费者 消费者1  剩余 生产者, 0
    11-04 19:44:59.250 11553-11621/com.test.videoplayer I/videoplayer: 没有产品了
    11-04 19:45:01.250 11553-11620/com.test.videoplayer I/videoplayer: 生产者  生产 1 
    11-04 19:45:01.250 11553-11622/com.test.videoplayer I/videoplayer: 消费者 消费者2  剩余 生产者, 0
    11-04 19:45:02.250 11553-11622/com.test.videoplayer I/videoplayer: 没有产品了
    11-04 19:45:04.250 11553-11620/com.test.videoplayer I/videoplayer: 生产者  生产 1 
    11-04 19:45:04.250 11553-11621/com.test.videoplayer I/videoplayer: 消费者 消费者1  剩余 生产者, 0
    11-04 19:45:05.260 11553-11621/com.test.videoplayer I/videoplayer: 没有产品了


    展开全文
  • 【摘要】本文介绍单生产者单消费者模型的队列...单生产者单消费者模型的队列操作过程是需要进行加锁的。生产者通过写索引控制入队操作,消费者通过读索引控制出队列操作。二者相互之间对索引是独享,存在竞争关系。

    1、引言
    本文介绍单生产者单消费者模型的队列。根据写入队列的内容是定长还是变长,分为单生产者单消费者定长队列和单生产者单消费者变长队列两种。单生产者单消费者模型的队列操作过程是不需要进行加锁的。生产者通过写索引控制入队操作,消费者通过读索引控制出队列操作。二者相互之间对索引是独享,不存在竞争关系。如下图所示:
    这里写图片描述
    2、单生产者单消费者定长队列

      这种队列要求每次入队和出队的内容是定长的,即生产者写入队列和消费者读取队列的内容大小事相同的。linux内核中的kfifo就是这种队列,提供了读和写两个索引。单生产者单消费者队列数据结构定义如下所示:
      

    typedef struct
    {
        uint32_t r_index; /*读指针*/
        uint32_t w_index; /*写指针*/
        uint32_t size;    /*缓冲区大小*/
        char *buff[0];    /*缓冲区起始地址*/
    }ring_buff_st;

    为了方便计算位置,设置队列的大小为2的次幂。这样可以将之前的取余操作转换为位操作,即r_index = r_index % size 与 r_index = r_index & (size -1)等价。位操作非常快,充分利用了二进制的特征。
    (1)队列初始状态,读写索引相等,此时队列为空。
    这里写图片描述
    (2)写入队列

    写操作即进行入队操作,入队有三种场景,

    2.1 写索引大于等于读索引
    这里写图片描述
    这里写图片描述
    2.2写索引小于读索引
    这里写图片描述
    2.3.写索引后不够写入一个
    这里写图片描述
    (3)读取队列

    读队列分为三种场景

    3.1写索引大于等于读索引
    这里写图片描述
    3.2写索引小于读索引
    这里写图片描述
    3.3.读索引后面不够一个
    这里写图片描述
    3、单生产者单消费者变长队列

      有些时候生产者每次写入的数据长度是不确定的,导致写入队列的数据时变长的。这样为了充分利用队列,需要增加一个结束索引,保证队列末尾至少能够写入一个数据。变长队列数据结构定义如下:
      详细见我博客关于边长数组介绍

    http://blog.csdn.net/xy010902100449/article/details/46522533
     

    typedef struct
    {
        uint32_t r_index; /*读指针*/
        uint32_t w_index; /*写指针*/
        uint32_t e_index; /*队列结束指针*/
        uint32_t size;    /*缓冲区大小*/
        char *buff[0];    /*缓冲区起始地址*/
    }ring_buff_st;
    展开全文
  • 现在需求里面,锁太拉低性能了。 所以想看看有木有需要锁的生产者消费者队列。 在网上搜索,发现都用的ringbuffer那样的循环队列。 可是怎么看怎么都安全啊。
  • 在这个案例中使用可重入锁来实现生产者消费模型。 在这个案例中分别使用两个线程对同一个对象进行操作,实现生产一个商品消费一个商品的操作。 多线程操作的三个重要步骤: 1. 线程操作资源类 2. 判断、干活(业务...

    在这个案例中使用可重入锁来实现生产者消费模型。

    在这个案例中分别使用两个线程对同一个对象进行操作,实现生产一个商品消费一个商品的操作。
    多线程操作的三个重要步骤:

    1. 线程操作资源类
    2. 判断、干活(业务处理)、唤醒通知
    3. 严防虚假唤醒

    在资源类UserShareData中义了两个方法
    producer() 方法用于生产一个商品
    consumer()方法用于消费一个商品

    在producer() 方法遵循多线程处理的3个步骤,因为使用的加锁机制,所以基本模式是这样:

    加锁
    
    try{
       1.
       循环判断{
          await() //使当前线程加入 await() 等待队列中,并释放当锁
       }
    
       2.具体的业务操作
       
       3.唤醒通知
    
    }catch(InterruptedException e){
       异常处理
    }finally{
       释放锁
    }


    1.判断
    首先判断number是否等于0,如果number !=0 说明已经生产了商品,此时应该阻塞生产操作,在多线程操作中,判断操作必须是在循环中进行,否则会引发虚假唤醒
    在循环判断内部使用condition.await(),功能就是生产者线程加入 await() 等待队列中,并释放当锁,当其他线程调用signal()会重新请求锁。与Object.wait()类似。

    2.干活
    就是进行具体的业务处理,在这个案例中,使得number+1操作来进行模拟

    3.唤醒通知
    使用condition.signalAll();来唤醒await()等待队列中的所有线程,与Object.notifyAll()功能类似

    consumer()是消费商品操作,与producer() 方法的模式一致,只是number-1操作,故不再赘述。

    class UserShareData{
        private int number = 0;
        private Lock lock = new ReentrantLock();
    
        // 一把锁,一体两面
        private Condition condition = lock.newCondition();
    
        // 生产商品
        public void producer(){
            lock.lock();
            try{
                // 1.判断 如果number !=0 说明已经有商品了,应该阻塞生产操作,否则就允许生产
                while(number != 0){
                    condition.await();
                }
    
                // 2.干活 用增加数量模拟生产了商品
                number +=1;
                System.out.println(Thread.currentThread().getName()+"\t 生产的商品数量:"+ number);
                // 3.通知唤醒
                condition.signalAll();
    
            }catch(InterruptedException e){
                e.printStackTrace();
            }finally{
                lock.unlock();
            }
        }
    
        public void consumer(){
            lock.lock();
            try{
                // 1.判断 如果number ==0 说明已经没有商品了,应该阻塞消费操作,否则就允许消费
                while(number == 0){
                    condition.await();
                }
    
                // 2.干活 用减少数量模拟消费了商品
                number -=1;
                System.out.println(Thread.currentThread().getName()+"\t 消费的商品数量:"+ number);
    
                // 3.通知唤醒
                condition.signalAll();
    
            }catch(InterruptedException e){
                e.printStackTrace();
            }finally{
                lock.unlock();
            }
    
        }
    
    }

    测试类:

    public class ProducerConsumerDemo_v2 {
        public static void main(String[] args) {
            UserShareData data = new UserShareData();
            new Thread( ()->{
                for (int i = 1; i < 10; i++) {
                    data.producer();
                }
            } ,"生产者").start();
    
            new Thread( ()->{
                for (int i = 1; i < 10; i++) {
                    data.consumer();
                }
            } ,"消费者").start();
    
        }
    }

    运行结果:

    生产者	 生产的商品数量:1
    消费者	 消费的商品数量:0
    生产者	 生产的商品数量:1
    消费者	 消费的商品数量:0
    生产者	 生产的商品数量:1
    消费者	 消费的商品数量:0
    生产者	 生产的商品数量:1
    消费者	 消费的商品数量:0
    生产者	 生产的商品数量:1
    消费者	 消费的商品数量:0
    生产者	 生产的商品数量:1
    消费者	 消费的商品数量:0
    生产者	 生产的商品数量:1
    消费者	 消费的商品数量:0
    生产者	 生产的商品数量:1
    消费者	 消费的商品数量:0
    生产者	 生产的商品数量:1
    消费者	 消费的商品数量:0

    可以看到有10对生产者 + 消费者的提示。
    在资源类的producer()和consumer()中都使用到了循环判断,为何会如此呢,看看jdk1.8原版中的描述:

    As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop: 

    synchronized (obj) {
     while (<condition does not hold>)
    	 obj.wait();
     ... // Perform action appropriate to condition
    }
    

    可是试着吧这俩方法中的while修改成if,然后使用2个生产者线程和2个消费者线程,得到的某次允运行结果如下:
     

    生产者1	 生产的商品数量:1
    消费者1	 消费的商品数量:0
    生产者1	 生产的商品数量:1
    消费者2	 消费的商品数量:0
    消费者1	 消费的商品数量:-1
    消费者1	 消费的商品数量:-2
    消费者1	 消费的商品数量:-3
    消费者1	 消费的商品数量:-4
    消费者1	 消费的商品数量:-5
    消费者1	 消费的商品数量:-6
    消费者1	 消费的商品数量:-7
    消费者1	 消费的商品数量:-8
    生产者1	 生产的商品数量:-7
    消费者2	 消费的商品数量:-8
    消费者2	 消费的商品数量:-9
    消费者2	 消费的商品数量:-10
    消费者2	 消费的商品数量:-11
    消费者2	 消费的商品数量:-12
    消费者2	 消费的商品数量:-13
    消费者2	 消费的商品数量:-14
    消费者2	 消费的商品数量:-15
    生产者2	 生产的商品数量:-14
    生产者1	 生产的商品数量:-13
    生产者2	 生产的商品数量:-12
    生产者1	 生产的商品数量:-11
    生产者2	 生产的商品数量:-10
    生产者1	 生产的商品数量:-9
    生产者2	 生产的商品数量:-8
    生产者1	 生产的商品数量:-7
    生产者2	 生产的商品数量:-6
    生产者1	 生产的商品数量:-5
    生产者2	 生产的商品数量:-4
    生产者1	 生产的商品数量:-3
    生产者2	 生产的商品数量:-2

    这个问题的根源就是在于产生了虚假唤醒,当恢复使用while判断之后测试正常,因此在线程中判断条件时必须使用循环判断。

    展开全文
  • 线程间通信:生产者消费者(都要加锁,且为同一把锁)

    多个线程都要加锁,并且加的是同一把锁

    public classStudent {

       Stringname;

       int age;

    }

     

    public classSetThread implementsRunnable {

     

       private Student s;

       private int x = 0;

     

       public SetThread(Student s) {

          this.s = s;

       }

     

       @Override

       public void run() {

          while (true) {

             synchronized (s) {

                if (x % 2 == 0) {

                    s.name = "林青霞";//刚走到这里,就被别人抢到了执行权

                    s.age = 27;

                }else{

                    s.name = "刘意"; //刚走到这里,就被别人抢到了执行权

                    s.age = 30;

                }

                x++;

             }

          }

       }

    }

     

    public classGetThread implementsRunnable {

       private Student s;

     

       public GetThread(Student s) {

          this.s = s;

       }

     

       @Override

       public void run() {

          while (true) {

             synchronized (s) {

                System.out.println(s.name + "---" + s.age);

             }

          }

       }

    }

     

    /*

     * 分析:

     *    资源类:Student

     *    设置学生数据:SetThread(生产者)

     *    获取学生数据:GetThread(消费者)

     *    测试类:StudentDemo

     *

     * 问题1:按照思路写代码,发现数据每次都是:null---0

     * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个

     * 如何实现呢?

     *    在外界把这个数据创建出来,通过构造方法传递给其他的类。

     *

     * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题

     *    A:同一个数据出现多次

     *    B:姓名和年龄不匹配

     * 原因:

     *    A:同一个数据出现多次

     *        CPU的一点点时间片的执行权,就足够你执行很多次。

     *    B:姓名和年龄不匹配

     *        线程运行的随机性

     * 线程安全问题:

     *    A:是否是多线程环境     

     *    B:是否有共享数据   

     *    C:是否有多条语句操作共享数据  

     * 解决方案:

     *    加锁。

     *    注意:

     *        A:不同种类的线程都要加锁。

     *        B:不同种类的线程加的锁必须是同一把。

     */

    public classStudentDemo {

       public static void main(String[] args) {

          //创建资源

          Students = newStudent();

         

          //设置和获取的类

          SetThreadst = newSetThread(s);

          GetThreadgt = newGetThread(s);

     

          //线程类

          Threadt1 = newThread(st);

          Threadt2 = newThread(gt);

     

          //启动线程

          t1.start();

          t2.start();

       }

    }

    展开全文
  • import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock;... * 生产者消费者 * Lock接口:出现替代了同步代码块或者同步函数,将同步的隐式锁操作变成现实锁操作, *
  • 讲到但生产者消费者的时候,运用了一个例子文章的博客地址: http://blog.csdn.net/morewindows/article/details/7577591 我个人不是很理解,当一个读线程和两个写线程同时使用一个临界区时,多缓冲区的作用从...
  • queue队列lock、condition加锁,解锁,阻塞机制,生产者消费者关系 queue队列lock、condition加锁,解锁,阻塞机制,生产者消费者关系 1、队列的属性 from queue import Queue """ 初始化Queue(maxsize)...
  • * 生产者消费者 * * */class Resrouce { private String name; private int count=1; private boolean flag=false; public synchronized void set(String name) { while(flag) try{th
  • public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
  • 1、前言    最近工作比较忙,加班较多,每天晚上回到家10点多了。我知道自己还能坚持多久,既然选择了就要做到最好。...单生产者单消费者模型的队列操作过程是需要进行加锁的。生产者通过写索引控制入队操作...
  • 1 单生产者单消费者无锁队列 Github项目地址:https://github.com/cameron314/readerwriterqueue 2 多生产者消费者无锁队列 另外这个作者还搞了一个并发的无锁队列, Github地址:...
  • 无锁队列之单生产者单消费者

    千次阅读 2016-12-19 15:46:00
    现实应用场景中经常会用到单生产者单消费者或多生产者消费者模型,例如一个写线程,接收到数据写入缓冲区,另一个线程读出并处理。为了尽可能减少锁所占用的时间,可使用gcc的一些原子操作来代替pthread_mutex_t或...
  • C++实现生产者消费者模型

    千次阅读 2020-09-17 08:50:04
    C++实现生产者消费者模型 C++实现生产者消费者模型1、实现细节1、单生产者-单消费者模型参考 C++实现生产者消费者模型 1、实现细节 具体的实现逻辑是构建一个queue来存储生产的数据,queue不满时可以生产,...
  • 一个循环缓冲buffer,一个读索引,一个写索引, 只有一个生产者,同时也只有一个消费者生产者维护写索引,同时只读 读索引, 消费者维护读索引,同时只读写索引。 我想请问,这种情况,是不是可以需要任何的...
  • 这里生产者消费者共同操作一个资源:缓冲池,因此每次操作的时候,需要给资源加锁,操作结束时,释放锁,这样才能做到资源同步。使用python实现,需要继承Thread类,获取锁对象,代码如下: # -*- coding:utf-8 -...
  • Java多种方式解决生产者消费者问题(十分详细)

    万次阅读 多人点赞 2018-08-16 08:40:50
    生产者消费者问题 一、问题描述 生产者消费者问题(Producer-consumer problem),也称有限缓冲问题(Bounded-buffer problem),是一个多线程同步问题的经典案例。生产者生成一定量的数据放到缓冲区中,...
  • 生产者消费者问题的几种实现

    千次阅读 2017-05-21 20:12:58
    Semaphore实现生产者消费者模型生产者消费者问题是一个经典的问题,一般情况下都会使用synchronized关键字来对生产和消费逻辑进行加锁 ,最近学习了下并发编程相关的基础知识,尝试使用其它的几种方法来实现生产者...
  • // 产品库全局变量, 生产者消费者操作该变量. typedef struct ItemRepository ItemRepository; void ProduceItem(ItemRepository *ir, int item) { std::unique_lock<std::mutex> lock(ir->mtx); //判断是否...
  • 根据上面链接所说的原理实现的单生产者单消费者无锁队列 bool __sync_bool_compare_and_swap (type *ptr, type oldval,type newval, ...) 函数提供原子的比较和交换,如果*ptr == oldval,就将newval写入*ptr。 ...
  • 两个线程一个生产者个一个消费者需求情景 两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个 涉及问题 同步问题:如何保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用标记或...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,842
精华内容 11,936
关键字:

单生产者单消费者不加锁