本文將說明如何使用信號量實現線程之間的互斥與同步?;コ怄i只有0,1兩中狀態,適合于線程對共享資源的獨占訪問,很多時候每個資源可以同時被有限的線程訪問,此時互斥鎖將無法滿足;條件變量同步也同樣存在這種問題。信號量實際是一種非負整型計數器,可以很好的控制線程之間資源訪問,互斥鎖能實現的功能,信號量同樣可以。
信號量控制資源共享主要是PV原語操作, PV原語是對整數計數器信號量sem的操作。一次 P操作使 sem減一,而一次 V操作使sem 加一。進程(或線程)根據信號量的值來判斷是否對公共資源具有訪問權限。當信號量sem 的值大于等于零時,該進程(或線程)具有公共資源的訪問權限;相反,當信號量 sem的值小于零時,該進程(或線程)就將阻塞直到信號量 sem的值大于等于 0 為止。
Linux 實現了POSIX 的無名信號量,主要用于線程間的互斥同步。這里主要介紹幾個常見函數。
· sem_init用于創建一個信號量,并能初始化它的值。
· sem_wait和sem_trywait相當于P操作,它們都能將信號量的值減一,兩者的區別在 于若信號量小于零時,sem_wait將會阻塞進程,而 sem_trywait則會立即返回。
· sem_post相當于V操作,它將信號量的值加一同時發出信號喚醒等待的進程。
· sem_getvalue用于得到信號量的值。
· sem_destroy用于刪除信號量。
所需頭文件 #i nclude
函數原型 int sem_init(sem_t *sem,int pshared,unsigned int value)
sem:信號量
pshared:決定信號量能否在幾個進程間共享。由于目前Linux還沒有實現進程間共享信號量,所以這個值只能夠取0
value:信號量初始化值
函數返回值 成功:0 ,出錯:-1
所需頭文件 #i nclude
函數原型
int sem_wait(sem_t *sem)
int sem_trywait(sem_t *sem)
int sem_post(sem_t *sem)
int sem_getvalue(sem_t *sem)
int sem_destroy(sem_t *sem)
函數傳入值 sem:信號量
函數返回值 成功:0 ,出錯:-1
從上面函數來看,實現線程之間同步信號量比互斥鎖使用起來相對容易一些,操作簡單,容易理解,適用范圍廣。
下面上一篇的問題用信號量來實現,線程使用部分沒變,主要改變了對資源的控制方式:(代碼本人親自編譯通過)
view plaincopy to clipboardprint?
01.#i nclude
02.#i nclude
03.#i nclude
04.#i nclude
05.#i nclude
06.#i nclude
07.
08.int g_Flag = 0;
09.sem_t sem_mutex; // 用于互斥
10.sem_t sem_syn; // 用于同步
11.
12.void *thread1( void *arg );
13.void *thread2( void *arg );
14.int main()
15.{
16. pthread_t tid1, tid2;
17. int rc1, rc2;
18.
19. sem_init( &sem_mutex, 0, 1 );
20. sem_init( &sem_syn, 0, 0 );
21. printf( “ Inter main !n” );
22.
23. rc2 = pthread_create( &tid2, NULL, thread2, NULL );
24. if( rc2 != 0 )
25. printf( “ %s, %d n”, __func__, strerror( rc2 ) );
26.
27. rc1 = pthread_create( &tid1, NULL, thread1, &tid2 );
28. if( rc1 != 0 )
29. printf( “ %s, %d n”, __func__, strerror(rc1) );
30. printf( “ Leave main!nn” );
31.
32. sem_wait( &sem_syn ); // 同步等待,阻塞
33. exit( 0 );
34.}
35.
36.void *thread1( void *arg )
37.{
38. pthread_t *ptid = NULL;
39. printf( “ Enter thread1n” );
40. printf( “ thread1 id: %u, g_Flag: %d n”, ( unsigned int )pthread_self(), g_Flag );
41.
42. if( sem_wait( &sem_mutex ) != 0)
43. {
44. perror(“ pthread1 sem_mutexn”);
45. }
46.
47. if( g_Flag == 2 )
48. sem_post( &sem_syn );
49. g_Flag = 1;
50.
51. if( sem_post( &sem_mutex ) != 0)
52. {
53. perror( “pthread1 sem_postn” );
54. }
55. printf( “ thread1 id: %u, g_Flag: %d n”,( unsigned int )pthread_self(), g_Flag );
56. printf( “Leave thread1 nn” );
57.
58. ptid = ( pthread_t *)arg;
59. printf( “ ptid = %u n”, *ptid );
60. pthread_join( *ptid, NULL );
61. pthread_exit(0 );
62.}
63.
64.void *thread2( void *arg )
65.{
66. printf( “ Enter thread2 !n” );
67. printf( “ thread2 id: %u , g_Flag: %d n”, ( unsigned int)pthread_self(), g_Flag );
68.
69. if( sem_wait( &sem_mutex ) != 0 )
70. {
71. perror( “thread2 sem_wait n” );
72. }
73.
74. if( g_Flag == 1 )
75. sem_post( &sem_syn );
76.
77. g_Flag = 2;
78.
79. if( sem_post( &sem_mutex ) != 0)
80. {
81. perror( “ thread2 sem_postn” );
82. }
83. printf( “ thread2 id: %u , g_Flag: %d n”, ( unsigned int )pthread_self(), g_Flag );
84. printf( “Leave thread2 nn” );
85.
86. pthread_exit(0);
87.}
責任編輯:ct
評論