Linux多线程之同步2 —— 生产者消费者模型

思路

生产者和消费者(互斥与同步)。资源用队列模拟(要上锁,一个时间只能有一个线程操作队列)。

m个生产者。拿到锁,且产品不满,才能生产。当产品满,则等待,等待消费者唤醒。当产品由空到不空,通知消费者。
n个消费者。拿到锁,且有产品,才能消费。当产品空,则等待,等待生产者唤醒。当产品由满到不满,通知生产者。
   
生产者条件:队列不满
消费者条件:队列不空
因此有两个条件变量。

代码

/*************************************************************************

  > File Name: main.c

  > Author: KrisChou

  > Mail:[email protected]

  > Created Time: Tue 26 Aug 2014 02:55:01 PM CST

 ************************************************************************/



#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))

        {

            pthread_cond_wait(&cond_pro, &mutex);

        }

        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 \n", 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 \n", 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 ;

}
 Makefile
main:main.c

    gcc -o $@ $< -lpthread

你可能感兴趣的:(生产者消费者)