歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

Linux 讀寫鎖的實現教程

要實現讀寫鎖,首先要知道讀寫鎖的特性,除了“讀者可並發,寫者要排它”之外還要考慮避免寫者饑餓的問題。綜合考慮後可以講讀寫鎖的實現總結為一下四點:
1.當已經被施加寫鎖的時候,讀鎖寫鎖都不能在施加(寫鎖只能鎖一次)
2.當已經被施加讀鎖時,還可以繼續施加讀鎖,但不能施加寫鎖
3.有等待的寫者時不能在獲取讀鎖(保證寫者優先)
4.解鎖時有如果寫者在等待,不能喚醒讀者。
我們使用互斥量(mutex)和條件變量來實現讀寫鎖,這也是大多數系統的實現方式。另外本文主要想說明的是讀寫鎖的實現思路,所以這裡只實現最基本的三個操作:申請讀鎖、申請寫鎖、解鎖。而不實現初始化、trylock、銷毀鎖等操作。
typedef struct

2. {

3. pthread_mutex_t rw_mutex; //對整個結構體提供互斥訪問

4. pthread_cond_t rw_condreaders;//用於通知申請讀鎖的線程

5. pthread_cond_t rw_condwriters;//用於通知申請寫鎖的線程

6. int rw_waitreaders; //等待申請讀鎖的線程數

7. int rw_waitwriters; //等待申請寫鎖的線程數

8. int rw_refcount; //表示讀寫鎖的狀態,如果是-1表示它是一個寫鎖

9. }pthread_rwlock_t; //0表示它是可用的,大於0表示當前容納的讀鎖數量

10.

11.

12. int pthread_rwlock_rdlock(pthread_rwlock_t *rw) //申請讀鎖
13. {

14. int result; //返回值(出錯狀態)
15.

16. pthread_mutex_lock(&rw->rw_mutex);

17. //當寫鎖正在使用時不能上讀鎖,當鎖可用但有線程等待申請寫鎖時一樣也不能上讀鎖,這一點體現出來“寫者優先”
18. while(rw->rw_refcount<0||rw->rw_waitwriters>0)

19. {

20. rw->rw_waitreaders++;

21. result=pthread_cond_wait(&rw->rw_condreaders,&rw->rw_mutex);//等待讀條件就緒

22. rw->rw_waitreaders--;

23. if(result!=0)

24. break;

25. }

26. if(result==0)

27. rw->rw_refcount++; //又有一個新的線程獲取了讀鎖

28.

29. pthread_mutex_unlock(&rw->rw_mutex);

30. return (result);

31. }

32.

33.

34. int pthread_rwlock_wrlock(pthread_rwlock_t *rw) //申請寫鎖
35. {

36. int result; //返回值(出錯狀態)
37.

38. pthread_mutex_lock(&rw->rw_mutex);

39. //這裡只檢查鎖是否可用

40. while(rw->rw_refcount!=0)

41. {

42. rw->rw_waitwriters++;

43. result=pthread_cond_wait(&rw->rw_condwriters,&rw->rw_mutex);//等待寫條件就緒

44. rw->rw_waitwriters--;

45. if(result!=0)

46. break;

47. }

48. if(result==0)

49. rw->rw_refcount=-1; //線程獲取了寫鎖

50.

51. pthread_mutex_unlock(&rw->rw_mutex);

52. return (result);

53. }

54.

55.

56.

57.

58. int pthread_rwlock_unlock(pthread_rwlock_t *rw)//釋放鎖(讀鎖、寫鎖)
59. {

60. int result;

61.

62.

63. pthread_mutex_lock(&rw->rw_mutex);

64. if(rw->refcount>0)

65. rw->refcount--;

66. else if(rw->refcount==-1)

67. rw->refcount=0;

68. else

69. printf("rw->refcount=%d\n",rw->refcount);

70. //先看是否有寫者在等待,如果有的話先喚醒寫者,這是“寫者優先”的另一體現

71. if(rw->rw_waitwriters>0)

72. {//不能寫成if(rw->rw_waitwriters>0&&rw->refcount==0)

73. if(rw->refcount==0)

74. result=pthread_cond_signal(&rw->rw_condwriters);

75. }

76. else if(rw->rw_waitreaders>0)

77. result=pthread_cond_signal(&rw->rw_condreaders);

78.

79.

80. pthread_mutex_unlock(rw->rw_mutex);

81. return result;

82. }
 

不能寫成if(rw->rw_waitwriters>0&&rw->refcount==0)的原因是:
這樣會造成寫者"饑餓",也就是應當保證,當有寫者在等待申請鎖的時候,不能在讓讀者來申請鎖,否則由於讀者可以多次加鎖,一個持續的讀請求流可能永遠阻塞某個等待的寫者。寫成if(rw->rw_waitwriters>0&&rw->refcount==0),當第一個條件滿足而第二個條件不滿足,也就是有寫者在等待,而還有讀者在使用鎖的情況,我們應該僅僅釋放一個讀鎖,別的什麼也不做,而這裡卻會執行else if,導致喚醒等待的讀者,使讀者獲取到鎖。

Copyright © Linux教程網 All Rights Reserved