zoukankan      html  css  js  c++  java
  • linux网络编程: 生产者消费者模型

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <pthread.h>
    #include <unistd.h>
    #define CNT 20           /* 最多生产20个产品 */
    
    /* 用队列模拟车间 */
    /* front和tail初始化均为0,tail是下一个资源生成的下一个数组空间下标 */
    typedef struct tag
    {
        int s_arr[CNT + 1] ;   /* 生产20个产品,必须有21个空间,因为如果空间都装满产品,无法区别队列满和队列空 */
        int s_front ;
        int s_tail ;
    }QUEUE,*pQUEUE ;
    QUEUE my_que ;
    /* 资源为空 */
    int que_empty(pQUEUE pq)
    {
        return pq ->s_front == pq -> s_tail ;
    }
    /* 资源为满 */
    int que_full(pQUEUE pq)
    {
        return  (pq -> s_tail + 1)% (CNT+1) == pq -> s_front ;
    }
    int que_cnt(pQUEUE pq)
    {
        return (pq -> s_tail  - pq ->s_front + CNT + 1)% (CNT + 1) ;
    }
    pthread_mutex_t  mutex ;
    pthread_cond_t cond_pro, cond_con ;
    
    void* pro_handler(void* arg)
    {
        pthread_detach(pthread_self());
        while(1)
        {
            pthread_mutex_lock(&mutex) ;
            while(que_full(&my_que))            //如果使用if 被唤醒时则不会再次判断是否满足 队列非空的条件 因为if只判断一次,再上次沉睡的时候就已经执行了,再次回来就会跳出 if的块语句
            {                                   //while则会在唤醒以后再次判断,如果队列依然还是满的,就继续沉睡。(因为是多线程,多个线程同时被唤醒,只有其中一个能拿到锁 ,生产队列其中一个线程)
                pthread_cond_wait(&cond_pro, &mutex); // 再次填满,所以其他没拿到锁的线程只有继续沉睡这一个选择。 否则造成队列上线溢出,例如我们规定 生产线上只能有20个产品,如果用if判断,就有可能
             }                                        //使队列有超过20的可能
            my_que.s_arr[my_que.s_tail ] = rand() % 1000 ;
            my_que.s_tail  = (my_que.s_tail + 1)% (CNT + 1) ;
            if(que_cnt(&my_que) == 1)
            {
                pthread_cond_broadcast(&cond_con);
            }
            printf("produce a product, total num : %d 
    ", que_cnt(&my_que));
            pthread_mutex_unlock(&mutex);
            sleep(rand()%3 + 1);
        }
    }
    void* con_handler(void* arg)
    {
        pthread_detach(pthread_self());
        while(1)
        {
            pthread_mutex_lock(&mutex);
            while(que_empty(&my_que))
            {
                pthread_cond_wait(&cond_con, &mutex);
            }
            my_que.s_front = (my_que.s_front + 1) % (CNT + 1) ;
            if(que_cnt(&my_que) == CNT - 1)
            {
                /*由于我们的主线程是等消费者线程创建完之后,再创建生产者线程,
                  因此一开始所有消费者线程都会挂起,在条件变量cond_pro的队列里排队
                  因此需要用broadcast通知所有消费者线程。
                  不然一次就通知一个生产者线程,就此消费者线程会抢锁。
                  当然,如果一开始主线程先创建生产者线程,再创建消费者线程,
                  由于生产者线程不会全部阻塞,因此可以使用signal来唤醒一个        */
                pthread_cond_broadcast(&cond_pro);
            }
            printf("consume a product, total num: %d 
    ", que_cnt(&my_que));
            pthread_mutex_unlock(&mutex);
            sleep(rand()%3 + 1);
        }
    
    }
    int main(int argc, char* argv[])//exe pro_num  con_num
    {
        int con_cnt , pro_cnt ;
        my_que.s_front = 0 ; 
        my_que.s_tail = 0 ;
        pro_cnt = atoi(argv[1]) ;
        con_cnt = atoi(argv[2]) ;
        srand(getpid());
        pthread_mutex_init(&mutex, NULL);
        pthread_cond_init(&cond_pro, NULL);
        pthread_cond_init(&cond_con, NULL);
        pthread_t* arr = (pthread_t*)calloc(con_cnt + pro_cnt, sizeof(pthread_t));
        int index = 0 ;
        while(con_cnt > 0)
        {
            pthread_create(arr + index , NULL, con_handler, NULL);
            index ++ ;
            con_cnt -- ;
        }
        sleep(5);
        while(pro_cnt > 0)
        {
            pthread_create(arr + index , NULL, pro_handler, NULL);
            index ++ ;
            pro_cnt -- ;
        }
        while(1) ;
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&cond_pro);
        pthread_cond_destroy(&cond_con);
        return 0 ;
    }

    注意

    无论是在生产者线程,还是在消费者线程中。标记黄色部分的判断条件必须用while。以生产者线程举例,当i>=CELL时,也就是i满时,此时执行pthread_cond_wait(&cond_cno,&mutex); 该生产者线程被挂起。必须等到消费者线程pthread_cond_signal(&cond_pro); 将其唤醒。但是消费者将其signal还不够,被挂其的生产者线程必须重新拿到锁,才可以被激活。但是,由于在消费者signal的同时,生产者并不能立即抢到锁,所以此时可能i值又改变变为大于等于10了。因此必须用while。不然可能导致i>10。

    (我们最初学习的时候用的是if(判断是否满队)) ,如果满队,则放锁并沉睡,问题出现在 被唤醒时,

    差别 :if 条件判断 被唤醒的时候(继续执行那一条代码) 直接执行对队的加1操作 不会判断是否满队

          while()条件判断,则在被唤醒时,先判断是否满队,如果满队的话则继续沉睡。

  • 相关阅读:
    451. Sort Characters By Frequency
    424. Longest Repeating Character Replacement
    68. Text Justification
    44. Wildcard Matching
    160. Intersection of Two Linked Lists
    24. Swap Nodes in Pairs
    93. 递归实现组合型枚举
    98. 分形之城
    97. 约数之和
    96. 奇怪的汉诺塔
  • 原文地址:https://www.cnblogs.com/DLzhang/p/3984973.html
Copyright © 2011-2022 走看看