C語言細(xì)致講解線程同步的集中方式
互斥鎖
使用互斥量完成對臨界區(qū)的資源的加鎖操作,使得同一時刻,對一個共享數(shù)據(jù)的使用只能又一個線程完成
例向屏幕上一次打印abcd四個字母
可以使用的是一個類似鎖連的思想 a 加完解開后拿b鎖依次類推
#define THRNUM 4 static pthread_mutex_t mut[4]; static int next(int n) { if(n + 1 == THRNUM) return 0; return n+1; } static void* pthreadfunc(void* p) { int n =(int)p; char c = 'a' + (int)p; while(1) { pthread_mutex_lock(mut + n); write(1,&c,1); pthread_mutex_unlock(mut + next(n)); } pthread_exit(NULL); } int main() { int i,err; pthread_t tid[THRNUM]; //創(chuàng)建線程 for(i = 0 ; i < THRNUM ;i++){ //初始化鎖 pthread_mutex_init(mut + i,NULL); //加鎖 pthread_mutex_lock(mut+i ); err = pthread_create(tid+i,NULL,pthreadfunc,(void*)i ); if(err != 0) { fprintf(stderr,"create:%s\n",strerror(err)); exit(1); } } //回收線程 pthread_mutex_unlock(mut + 0); alarm(5); for(i = 0 ; i < THRNUM ;i++){ pthread_join(tid+i,NULL); } }
條件變量
條件變量并不是鎖而是一種阻塞機(jī)制,使得我們的程序在某些特定的條件,比如生產(chǎn)者生產(chǎn)達(dá)到上限未消費,此時使用條件變量(加上while對條件的判斷)來阻塞生產(chǎn),讓生產(chǎn)者消費
#include<stdio.h> #include<unistd.h> #include<pthread.h> #include<stdlib.h> #include<string.h> int begnum=0; static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; typedef struct _prodinfo { int num; struct _prodinfo *next; }prod; struct _prodinfo* head=NULL; /* 條件變量可以引起阻塞并非鎖 */ void *thr_produce(void*arg) { while(1) { prod* pd = malloc(sizeof(struct _prodinfo)); pd->num=begnum++; pthread_mutex_lock(&mut); pd->next=head; head=pd; printf(" -%ld號線程生產(chǎn)%d產(chǎn)品\n",pthread_self(),pd->num); pthread_mutex_unlock(&mut); pthread_cond_signal(&cond); sleep(rand()%4); } } void* thr_con(void* arg) { prod* pro=NULL; while(1) { pthread_mutex_lock(&mut); while(head==NULL) pthread_cond_wait(&cond,&mut); pro = head; head=head->next; printf(" -%ld號線程消費%d產(chǎn)品\n",pthread_self(),pro->num); pthread_mutex_unlock(&mut); free(pro); sleep(rand()%4); } } int main() { pthread_t cid,pid; int err1=pthread_create(&pid,NULL,thr_produce,NULL); if(err1) { fprintf(stderr,"pthread_creat():%s\n",strerror(err1)); exit(1); } int err2=pthread_create(&cid,NULL,thr_con,NULL); if(err2) { fprintf(stderr,"pthread_creat():%s\n",strerror(err1)); exit(1); } pthread_join(pid,NULL); pthread_join(cid,NULL); }
信號量
介紹以下信號量是進(jìn)化版的互斥量,允許多個線程訪問共享資源與條件變量和互斥量類此的操作,在進(jìn)程和線程中均可以使用
int sem_init(sem_t *sem, int pshared, unsigned int value); int sem_destroy(sem_t *sem); Link with -pthread.
sem為定義的信號量,傳出型參數(shù)
pshared
- 0 代表線程信號量
- 1 代表進(jìn)程信號量
alue 為定義的信號量個數(shù)
int sem_wait(sem_t *sem); int sem_trywait(sem_t *sem); int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
申請信號量,申請成功value–,當(dāng)value為0 則阻塞
int sem_post(sem_t *sem);
釋放信號量value++
例 信號量實現(xiàn)生產(chǎn)者消費者模型
sem_t pro_sem,con_sem; #define semcnt 5 int i=0; int queue[semcnt]; int beginnum = 100; void *thr_produce(void*arg) { while(1) { sem_wait(&pro_sem);//生產(chǎn)者申請資源 pro_sem每被占用一次--一次 當(dāng)為0時則阻塞 printf("%ld 線程生產(chǎn)了 %d\n",pthread_self(),beginnum); queue[(i++)%semcnt]= beginnum++; sem_post(&con_sem);//為消費者的信號量釋放資源pro_sem每被釋放一次++一次 sleep(rand()%4); } return NULL; } void* thr_con(void* arg) { int i=0; int num=0; while(1) { sem_wait(&con_sem); num = queue[(i++)%semcnt]; printf("%ld 線程消費了 %d\n",pthread_self(),num); sem_post(&pro_sem); sleep(rand()%3); } return NULL; } int main() { sem_init(&pro_sem,0,semcnt); sem_init(&con_sem,0,0); //消費者初始默認(rèn)沒有產(chǎn)品 pthread_t tid[2]; int err1=pthread_create(&tid[0],NULL,thr_produce,NULL); if(err1) { fprintf(stderr,"pthread_creat():%s\n",strerror(err1)); exit(1); } int err2=pthread_create(&tid[1],NULL,thr_con,NULL); if(err2) { fprintf(stderr,"pthread_creat():%s\n",strerror(err1)); exit(1); } pthread_join(tid[0],NULL); pthread_join(tid[1],NULL); sem_destroy(&pro_sem); sem_destroy(&con_sem); }
讀寫鎖
讀寫鎖 與互斥量類似,但是讀寫鎖允許更高的并行性,其特性為:寫?yīng)氄?,讀共享
讀寫鎖實質(zhì)上是一把鎖,有不同的狀態(tài),寫鎖的優(yōu)先級高
讀寫鎖的三種狀態(tài)
- 讀模式下加鎖(讀鎖)
- 寫模式下加鎖(寫鎖)
- 不加鎖狀態(tài)
讀寫鎖的特性: 讀鎖可以共享讀的狀態(tài),當(dāng)讀鎖加上時,阻塞寫鎖的加鎖
即使讀鎖加上時 后面的 寫鎖依然會被阻塞,當(dāng)前面讀鎖釋放時才能加成功
pthread_rwlock_t rwlock =PTHREAD_RWLOCK_INITIALIZER; int beginum=100; void*thr_Wr(void*arg) { while(1) { pthread_rwlock_wrlock(&rwlock); printf("-寫線程--beginum = %d\n",beginum++); usleep(2000);//模擬占用時間 pthread_rwlock_unlock(&rwlock); usleep(2000);//簡單防止再搶鎖的方法但不建議使用 } return NULL; } void*thr_ead(void*arg) { while (1) { pthread_rwlock_rdlock(&rwlock); printf("-讀讀線程--beginum = %d\n",beginum); usleep(2000);//模擬占用時間 pthread_rwlock_unlock(&rwlock); usleep(2000);//簡單防止再搶鎖的方法但不建議使用 } return NULL; } int main() { int n=8,i=0; pthread_t tid[8]; for(i = 0; i<5;i++) { pthread_create(&tid[i],NULL,thr_ead,NULL); } for(; i<8;i++) { pthread_create(&tid[i],NULL,thr_Wr,NULL); } for(i = 0; i<8;i++) { pthread_join(tid[i],NULL); } pthread_rwlock_destroy(&rwlock); }
到此這篇關(guān)于C語言細(xì)致講解線程同步的集中方式的文章就介紹到這了,更多相關(guān)C語言線程同步內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實現(xiàn)高性能轉(zhuǎn)換大小寫算法示例
大小寫轉(zhuǎn)換是我們作為一名程序員經(jīng)常會遇到,也必須要會的一個功能,下面這篇文章主要給大家介紹了關(guān)于C++實現(xiàn)高性能轉(zhuǎn)換大小寫算法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來一起看看吧。2018-01-01C語言中十六進(jìn)制轉(zhuǎn)十進(jìn)制兩種實現(xiàn)方法
這篇文章主要介紹了C語言中十六進(jìn)制轉(zhuǎn)十進(jìn)制兩種實現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下2017-01-01C++實現(xiàn)拷貝構(gòu)造函數(shù)的方法詳解
拷貝構(gòu)造函數(shù)是構(gòu)造函數(shù)的一個重載,因此顯式的定義了拷貝構(gòu)造,那么編譯器也不再默認(rèn)生成構(gòu)造函數(shù)。本文主要介紹了C++實現(xiàn)拷貝構(gòu)造函數(shù)的方法,需要的可以參考一下2022-09-09C語言數(shù)據(jù)結(jié)構(gòu)順序表的進(jìn)階講解
程序中經(jīng)常需要將一組數(shù)據(jù)元素作為整體管理和使用,需要創(chuàng)建這種元素組,用變量記錄它們,傳進(jìn)傳出函數(shù)等。一組數(shù)據(jù)中包含的元素個數(shù)可能發(fā)生變化,順序表則是將元素順序地存放在一塊連續(xù)的存儲區(qū)里,元素間的順序關(guān)系由它們的存儲順序自然表示2022-04-04