lesson4 線程同步

1. 互斥量mutex

2. 讀寫鎖:pthread_rwlock_t rwlock//非常適合讀次數大於寫次數的程序

讀寫鎖的三種狀態:讀模式加鎖、寫模式加鎖、不加鎖。一次只有一個線程佔用寫模式的讀寫鎖,但是多個線程可以同時佔用讀模式的讀寫鎖。

讀寫鎖在寫加鎖狀態時,在被解鎖前,所有試圖這個鎖加鎖的線程將會阻塞。以讀加鎖時,所有試圖讀模式加鎖的線程都能獲得訪問權限,但是如果希望以寫模式加鎖,則必須阻塞直到所有線程釋放鎖。

讀寫鎖一讀模式加鎖時,如果有其他線程試圖以寫模式加鎖,那麼讀寫鎖會阻塞隨後的讀模式加鎖請求,避免鎖長期佔用。


pthread_rwlock_init初始化鎖

pthread_rwlock_destroy銷燬鎖


pthread_rwlock_rdlock //讀模式加鎖

pthread_rwlock_tryrdlock


pthread_rwlock_wrlock //寫模式加鎖

pthread_rwlock_trywrlock


pthread_rwlock_unlock //解鎖


3. 條件變量

當互斥量被鎖住以後發現當前線程還是無法完成自己的操作,那麼它應該釋放互斥量,讓其他線程工作:

a. 輪詢的方法,不停的查詢你需要的條件;

b. 系統幫你查詢條件,使用條件變量pthread_condi_t cond

pthread_cond_init //初始化

pthread_cond_destroy //銷燬

pthread_cond_wait //等待條件爲真

參數中的互斥量對條件進行保護,傳遞鎖住的互斥量

函數將線程放到等待條件的線程列表上,然後對互斥量進行解鎖。當條件滿足時函數返回,返回以後繼續對互斥量加鎖。

pthread_cond_timedwait //指定時間條件不滿足,那麼函數返回


條件滿足時需要喚醒等待條件的線程

pthread_cond_boradcast //喚醒等待條件的所有線程

pthread_cond_signal //至少喚醒等待條件的一個線程

一定要在條件改變以後再喚醒進程


4. 一個很好的例子:說明了條件變量的使用


#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <time.h>  
#include <unistd.h>  
#include <pthread.h>  
  
#define BUFFER_SIZE         5       //產品庫存大小  
#define PRODUCT_CNT         50      //產品生產總數   
  
struct product_cons  
{  
	int buffer[BUFFER_SIZE];  //生產產品值  
	pthread_mutex_t lock;     //互斥鎖 volatile int  
    int readpos, writepos;    //讀寫位置  
    pthread_cond_t notempty;  //條件變量,非空  
   pthread_cond_t notfull;   //非滿  
}buffer;  
  
void init(struct product_cons *p)  
{  
	pthread_mutex_init(&p->lock, NULL);     //互斥鎖  
    pthread_cond_init(&p->notempty, NULL);  //條件變量  
    pthread_cond_init(&p->notfull, NULL);   //條件變量  
    p->readpos = 0;                         //讀寫位置  
    p->writepos = 0;  
}  
  
void fini(struct product_cons *p)  
{  
    pthread_mutex_destroy(&p->lock);     //互斥鎖  
	pthread_cond_destroy(&p->notempty);  //條件變量  
	pthread_cond_destroy(&p->notfull);   //條件變量  
	p->readpos = 0;                      //讀寫位置  
	p->writepos = 0;  
}  
  
void cleanup_handler(void *arg)  
{  
	printf("cleanup_handler exec!\n");  
	pthread_mutex_t *lock = (pthread_mutex_t*)arg;  
	pthread_mutex_unlock(lock); //解鎖  
}  
  
//存儲 一個數據 到 bufferr  
void put(struct product_cons *p, int data) //輸入產品子函數  
{  
    pthread_mutex_lock(&p->lock); //上鎖  

	/*等待,直到 buffer 不爲 滿*/  
	while((p->writepos + 1) % BUFFER_SIZE == p->readpos) //測試空間是否已滿  
	{  
		printf("producer wait for not full\n");  
		pthread_cond_wait(&p->notfull, &p->lock); //阻塞等待  
		//這裏,生產者 notfull 等待消費者 pthread_cond_signal(&p->notfull);信號  
		//如果,消費者發送了 signal 信號,表示有了 空閒  
	}  

	p->buffer[p->writepos] = data; //寫數據  
	p->writepos++;  
	if(p->writepos >= BUFFER_SIZE) //如果寫到 尾部,返回  
		p->writepos = 0;  
	pthread_cond_signal(&p->notempty); //發送有數據信號  
	pthread_mutex_unlock(&p->lock); //解鎖        
}  

//讀,移除 一個數據 從 buffer  
int get(struct product_cons *p)  
{  
	int data = 0;
	pthread_mutex_lock(&p->lock);
	/*等待,直到不爲空*/  
	while(p->writepos == p->readpos)  
	{  
		printf("consumer wait for not empty\n");  
		pthread_cond_wait(&p->notempty,&p->lock);  
	}  
	
	/*讀 一個 數據*/  
	data = p->buffer[p->readpos];          
	p->readpos++;  

	if(p->readpos >= BUFFER_SIZE) //如果讀到 尾  
		p->readpos = 0;  

	pthread_cond_signal(&p->notfull);
	pthread_mutex_unlock(&p->lock);  

	return data;      
}  

void *producer(void *data) //子線程 ,生產
{
	int n;  
	for(n = 1; n <= 50; ++n) //生產 50 個產品  
	{  
		sleep(1);  
		printf("put the %d product\n",n);
		put(&buffer,n);  
	}  

	printf("producer stopped\n");  

	return NULL;  
}  

void *consumer(void *data)  
{  
	static int cnt = 0;  
	while(1)  
	{  
		sleep(2);  
		printf("get the %d product\n", get(&buffer));  
		if(++cnt == PRODUCT_CNT)  
			break;  
	}  

	printf("consumer stopped\n");  
	return NULL;  
}  

int main(int argc, char *argv[])  
{  
	pthread_t th_a,th_b;
	void *retval;  

	init(&buffer);  

	pthread_create(&th_a, NULL, producer, 0);  
	pthread_create(&th_b, NULL, consumer, 0);  

	pthread_join(th_a, &retval);  
	pthread_join(th_b, &retval);  

	fini(&buffer);  

	return 0;  
}  

執行結果:



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章