讀寫鎖
1、概述
讀寫鎖與互斥量類似,不過讀寫鎖允許更高的並行性。互斥量要么是鎖住狀態,要么是不加鎖狀態,而且一次只有一個線程對其加鎖。讀寫鎖可以有三種狀態:讀模式下加鎖狀態,寫模式下加鎖狀態,不加鎖狀態。一次只有一個線程可以占有寫模式的讀寫鎖,但是多個線程可用同時占有讀模式的讀寫鎖。讀寫鎖也叫做共享-獨占鎖,當讀寫鎖以讀模式鎖住時,它是以共享模式鎖住的,當它以寫模式鎖住時,它是以獨占模式鎖住的。
2、讀寫鎖API
讀寫鎖的數據類型為pthread_rwlock_t。如果這個類型的某個變量是靜態分配的,那么可通過給它賦常值PTHREAD_RWLOCK_INITIALIZER來初始化它。
獲取和釋放讀寫鎖:
int pthread_rwlock_rdlock(pthread_rwlock_t *rwptr); //獲取一個讀出鎖
int pthread_rwlock_wrlock(pthread_rwlock_t *rwptr); //獲取一個寫入鎖
int pthread_rwlock_unlock(pthread_rwlock_t *rwptr); //釋放一個寫入鎖或者讀出鎖
都返回:成功時為0,出錯時為正的Exxx值
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwptr);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwptr);
都返回:成功時為0,出錯時為正的Exxx值
讀寫鎖屬性:
int pthread_rwlock_init(pthread_rwlock_t *rwptr, const pthread_rwlockattr_t *attr)
int pthread_rwlock_destroy(pthread_rwlock_t *rwptr);
都返回:成功時為0,出錯時為正的Exxx值
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
都返回:成功時為0,出錯時為正的Exxx值
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *valptr);
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int valptr);
都返回:成功時為0,出錯時為正的Exxx值
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <unistd.h> 5 #include <pthread.h> 6 #include <errno.h> 7 8 #define MAXDATA 1024 9 #define MAXREDER 100 10 #define MAXWRITER 100 11 struct 12 { 13 pthread_rwlock_t rwlock; 14 char datas[MAXDATA]; 15 } shared = { 16 PTHREAD_RWLOCK_INITIALIZER 17 }; 18 19 void *reader(void *arg); 20 void *writer(void *arg); 21 22 int main(int argc,char *argv[]) 23 { 24 int i,readercount,writercount; 25 pthread_t tid_reader[MAXREDER],tid_writer[MAXWRITER]; 26 if(argc != 3) 27 { 28 printf("usage : <reader_writer> #<readercount> #<writercount>\n"); 29 exit(0); 30 } 31 readercount = atoi(argv[1]); 32 writercount = atoi(argv[2]); 33 pthread_setconcurrency(readercount+writercount); 34 for(i=0;i<writercount;++i) 35 pthread_create(&tid_writer[i],NULL,writer,NULL); 36 sleep(1); 37 for(i=0;i<readercount;++i) 38 pthread_create(&tid_reader[i],NULL,reader,NULL); 39 for(i=0;i<writercount;++i) 40 pthread_join(tid_writer[i],NULL); 41 for(i=0;i<readercount;++i) 42 pthread_join(tid_reader[i],NULL); 43 exit(0); 44 } 45 void *reader(void *arg) 46 { 47 pthread_rwlock_rdlock(&shared.rwlock); 48 printf("Reader begins read message.\n"); 49 sleep(1); 50 printf("Read message is: %s\n",shared.datas); 51 pthread_rwlock_unlock(&shared.rwlock); 52 return NULL; 53 } 54 55 void *writer(void *arg) 56 { 57 char datas[MAXDATA]; 58 pthread_rwlock_wrlock(&shared.rwlock); 59 printf("Writers begings write message.\n"); 60 printf("Enter the write message: \n"); 61 gets(datas); 62 strcat(shared.datas,datas); 63 pthread_rwlock_unlock(&shared.rwlock); 64 return NULL; 65 }
打印輸出
[root@localhost pthread_rwlock]# ./run 5 1 Writers begings write message. Enter the write message: sdfs Reader begins read message. Reader begins read message. Reader begins read message. Reader begins read message. Reader begins read message. Read message is: sdfs Read message is: sdfs Read message is: sdfs Read message is: sdfs Read message is: sdfs [root@localhost pthread_rwlock]#
我在read中加入sleep,看家其他read線程也進入了,表明一次只有一個線程可以占有寫模式的讀寫鎖,但是多個線程可用同時占有讀模式的讀寫鎖。
另外請關注pthread_setconcurrency();
最近在code review一些人的代碼的時候,發現了一個問題,就是很少人關注pthread_setconcurrency()函數,其實這個函數在pthread中是一個很重要的函數。在linux下,如果你忽略了這個函數的使用,那么能夠並發的線程數目由實現者來控制,對於系統調度的效率而言往往不是什么好的事情,因為默認的設置往往不是最佳的。
更為糟糕的是,如果在某些系統中,如果你不調用pthread_setconcurrency()函數,那么系統中的運行的線程僅僅是第一個被創建的線程,其他線程根本不會被運行。比如在solaris 2。6中就有這些情況。為了在unix或者是linux系統上使移植更加的容易,請不要忘記在適當的地方調用次函數,清晰的告訴系統我們使用的線程個數。雖然在某些系統上,這個調用是徒勞的,但是它的使用增強的移植性!