Linux下多線程編程的互斥與同步
本文將說(shuō)明如何使用信號(hào)量實(shí)現(xiàn)線程之間的互斥與同步?;コ怄i只有0,1兩中狀態(tài),適合于線程對(duì)共享資源的獨(dú)占訪問(wèn),很多時(shí)候每個(gè)資源可以同時(shí)被有限的線程訪問(wèn),此時(shí)互斥鎖將無(wú)法滿足;條件變量同步也同樣存在這種問(wèn)題。信號(hào)量實(shí)際是一種非負(fù)整型計(jì)數(shù)器,可以很好的控制線程之間資源訪問(wèn),互斥鎖能實(shí)現(xiàn)的功能,信號(hào)量同樣可以。
信號(hào)量控制資源共享主要是PV原語(yǔ)操作, PV原語(yǔ)是對(duì)整數(shù)計(jì)數(shù)器信號(hào)量sem的操作。一次 P操作使 sem減一,而一次 V操作使sem 加一。進(jìn)程(或線程)根據(jù)信號(hào)量的值來(lái)判斷是否對(duì)公共資源具有訪問(wèn)權(quán)限。當(dāng)信號(hào)量sem 的值大于等于零時(shí),該進(jìn)程(或線程)具有公共資源的訪問(wèn)權(quán)限;相反,當(dāng)信號(hào)量 sem的值小于零時(shí),該進(jìn)程(或線程)就將阻塞直到信號(hào)量 sem的值大于等于 0 為止。
Linux 實(shí)現(xiàn)了POSIX 的無(wú)名信號(hào)量,主要用于線程間的互斥同步。這里主要介紹幾個(gè)常見(jiàn)函數(shù)。
· sem_init用于創(chuàng)建一個(gè)信號(hào)量,并能初始化它的值。
· sem_wait和sem_trywait相當(dāng)于P操作,它們都能將信號(hào)量的值減一,兩者的區(qū)別在 于若信號(hào)量小于零時(shí),sem_wait將會(huì)阻塞進(jìn)程,而 sem_trywait則會(huì)立即返回。
· sem_post相當(dāng)于V操作,它將信號(hào)量的值加一同時(shí)發(fā)出信號(hào)喚醒等待的進(jìn)程。
· sem_getvalue用于得到信號(hào)量的值。
· sem_destroy用于刪除信號(hào)量。
所需頭文件 #i nclude
函數(shù)原型 int sem_init(sem_t *sem,int pshared,unsigned int value)
sem:信號(hào)量
pshared:決定信號(hào)量能否在幾個(gè)進(jìn)程間共享。由于目前Linux還沒(méi)有實(shí)現(xiàn)進(jìn)程間共享信號(hào)量,所以這個(gè)值只能夠取0
value:信號(hào)量初始化值
函數(shù)返回值 成功:0 ,出錯(cuò):-1
所需頭文件 #i nclude
函數(shù)原型
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)
函數(shù)傳入值 sem:信號(hào)量
函數(shù)返回值 成功:0 ,出錯(cuò):-1
從上面函數(shù)來(lái)看,實(shí)現(xiàn)線程之間同步信號(hào)量比互斥鎖使用起來(lái)相對(duì)容易一些,操作簡(jiǎn)單,容易理解,適用范圍廣。
下面上一篇的問(wèn)題用信號(hào)量來(lái)實(shí)現(xiàn),線程使用部分沒(méi)變,主要改變了對(duì)資源的控制方式:(代碼本人親自編譯通過(guò))
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.}