使用pthread_mutex_t與條件變數pthread_cond_t的組合來實現生產者和消費者

不凋零的樹葉發表於2020-11-14

使用pthread_mutex_t與條件變數pthread_cond_t的組合來實現生產者和消費者;以下是基本的流程圖:

#include <time.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include <semaphore.h>
#include <pthread.h>

#define SUCCESS 0
#define FAILE   -1
#define true 1
#define false 0
//此次是多個消費者對應一個生產者的模型、
//使用的是互斥量pthread_mutex_t與條件變數pthread_cond_t的組合來實現,匯入pthread_cond_t主要是能避免多執行緒帶來的死鎖的問題
#define CONSUMERS_COUNT 3
#define PRODUCERS_COUNT 1

typedef struct tag_THREAD_S
{
    pthread_t             tBaseTh_id[CONSUMERS_COUNT+PRODUCERS_COUNT];
    pthread_mutex_t       m_Base_lock;
    pthread_cond_t        c_Base_cond;
    int                   bBaseThdStartFlg;
}THREAD_S;

THREAD_S s_BaseThread;
int share_variable = 0 ;//生產的產品

void *ThreadConsumerFun(void *pvoid){//消費者
	//struct timespec ts;
	int num = (int*)pvoid;
    
	while(s_BaseThread.bBaseThdStartFlg){
		 pthread_mutex_lock(&s_BaseThread.m_Base_lock);
		 while ( share_variable == 0 ){
         	printf( "consumer :%d begin wait a condition...\n", num ) ;
         	pthread_cond_wait( &s_BaseThread.c_Base_cond, &s_BaseThread.m_Base_lock );//等待條件變數的時候會解鎖互斥鎖m_Base_lock
         	//sleep():執行緒等待,等待期間執行緒無法喚醒;(注意是期間);
			//pthread_cond_wait ;執行緒等待訊號觸發,如果沒有訊號觸發,無限期等待下去;
			//pthread_cond_timedwait :執行緒等待一定的時間,如果超時或有訊號觸發,執行緒喚醒;
			//詳細區別和應用可參考部落格:https://www.cnblogs.com/yuanchenhui/p/thread_signal.html
       	 }
      	 share_variable--;//消費了
      	 printf( "consumer :%d end consumer.\n", num ) ;
		 pthread_mutex_unlock(&s_BaseThread.m_Base_lock);
		 sleep(6);
	}
	sleep(1);
}

void *ThreadProducerFun(void *pvoid){//生產者
	//struct timespec ts;
	int num = (int*)pvoid;
    
	while(s_BaseThread.bBaseThdStartFlg){
		 pthread_mutex_lock(&s_BaseThread.m_Base_lock);
		 printf( "producer :%d begin produce product...\n", num );
      	 share_variable++;
      	 printf( "producer :%d end produce product...\n", num );
      	 pthread_mutex_unlock( &s_BaseThread.m_Base_lock );//這一步要先於pthread_cond_signal;
      	 pthread_cond_signal( &s_BaseThread.c_Base_cond );
      	 printf( "producer: %d to notified consumer the condition variable...\n", num );
		 sleep(1);
	}
	sleep(1);
}

int Base_int(void){
	int ret=0;
	printf( "init .\n" );
	//int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);//函式原形
	pthread_mutex_init(&s_BaseThread.m_Base_lock,NULL);//初始化互斥鎖
    pthread_condattr_t condAttr;
    (void)pthread_condattr_init(&condAttr);
	//(void)pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);//設定並同步系統時間
    (void)pthread_cond_init(&s_BaseThread.c_Base_cond, &condAttr);
    (void)pthread_condattr_destroy(&condAttr);
    //int pthread_mutex_lock(pthread_mutex_t *mutex);//原形
    //int pthread_mutex_trylock(pthread_mutex_t *mutex);//不阻塞
	pthread_mutex_lock(&s_BaseThread.m_Base_lock);
    s_BaseThread.bBaseThdStartFlg = true;
    //int pthread_mutex_unlock(pthreadd_mutex_t *mutex);
    pthread_mutex_unlock(&s_BaseThread.m_Base_lock);
	return ret;
}

int Base_Deint(void){
	int ret =0;
	int i =0;
	printf( "Deinit .\n" );
	pthread_mutex_lock(&s_BaseThread.m_Base_lock);
	s_BaseThread.bBaseThdStartFlg = false;
	//pthread_cond_signal(&s_BaseThread.c_Base_cond);//傳送訊號;
	pthread_mutex_unlock(&s_BaseThread.m_Base_lock);
	for(i=0;i<CONSUMERS_COUNT+PRODUCERS_COUNT;i++){
		if (-1 != s_BaseThread.tBaseTh_id[i])
		{
			 pthread_join(s_BaseThread.tBaseTh_id[i], NULL);//執行緒連線,當前執行緒阻塞,等待edog執行緒結束才會繼續執行;
			 s_BaseThread.tBaseTh_id[i]= -1;
		}
	}
	//int pthread_mutex_destroy(pthread_mutex_t *mutex);
	pthread_mutex_destroy(&s_BaseThread.m_Base_lock);//銷燬互斥鎖
	pthread_cond_destroy(&s_BaseThread.c_Base_cond);//銷燬訊號量
	memset(&s_BaseThread, 0, sizeof(THREAD_S));//復位歸零
	return ret;
}

int main(){

	int ret=0;
	int i=0;
	ret=Base_int();
	if(ret){
		printf("init error!\n");
	}
	for(i=0;i<CONSUMERS_COUNT;i++){//建立消費者
		ret = pthread_create(&s_BaseThread.tBaseTh_id[i], NULL, ThreadConsumerFun,(void*)i);
		if(SUCCESS != ret)//建立失敗
		{
		    printf("create ThreadConsumerFun:%d failed ! ret %d\n", i,ret);
			pthread_mutex_lock(&s_BaseThread.m_Base_lock);
		    s_BaseThread.bBaseThdStartFlg = false;
		    pthread_mutex_unlock(&s_BaseThread.m_Base_lock);
		    
		    pthread_mutex_destroy(&s_BaseThread.m_Base_lock);
		    pthread_cond_destroy(&s_BaseThread.c_Base_cond);
		    return ret;  
		}
	}

	for(i=CONSUMERS_COUNT;i<CONSUMERS_COUNT+PRODUCERS_COUNT;i++){//建立生產者
		ret = pthread_create(&s_BaseThread.tBaseTh_id[i], NULL, ThreadProducerFun, (void*)(i-CONSUMERS_COUNT));
		if(SUCCESS != ret)//建立失敗
		{
		    printf("create ThreadProducerFun :%d failed ! ret %d\n",(i-CONSUMERS_COUNT), ret);
			pthread_mutex_lock(&s_BaseThread.m_Base_lock);
		    s_BaseThread.bBaseThdStartFlg = false;
		    pthread_mutex_unlock(&s_BaseThread.m_Base_lock);
		    
		    pthread_mutex_destroy(&s_BaseThread.m_Base_lock);
		    pthread_cond_destroy(&s_BaseThread.c_Base_cond);
		    return ret;  
		}
	}

	for ( i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; i++ ) 
   	{
      pthread_join( s_BaseThread.tBaseTh_id[i], NULL );
   	}

    while(1){
    	sleep(2);

    }

    //退出前Deinit
    ret=Base_Deint();
    if(ret){
    	printf(" Deint error !\n");
    }
	return 0;
}

執行結果:(我改變了sleep引數,這結果表明生產者生產的是充足的,即share_variable 後續沒有為0)

 

 

相關文章