Linux多線程
1.線程概述
線程是一個進程內的基本調度單位,也可以稱為輕量級進程。線程是在共用記憶體空間中並發的多道執行路徑,它們共用一個進程的資源,如檔案描述和訊號處理。因此,大大減少了環境切換的開銷。一個進程可以有多個線程,也就
是有多個線程式控制製表及堆棧寄存器,但卻共用一個使用者地址空間。
2.線程實現
線程建立pthread_create()
所需標頭檔#include <pthread.h>
函數原型int pthread_create ((pthread_t *thread, pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg))
thread:線程標識符
attr:線程屬性設定
start_routine:線程函數的起始地址
arg:傳遞給start_routine的參數
函數傳回值 成功:0 出錯:-1
線程退出pthread_exit();
所需標頭檔#include <pthread.h>
函數原型void pthread_exit(void *retval)
函數傳入值retval:pthread_exit()調用者線程的傳回值,可由其他函數如pthread_join 來檢索擷取
等待線程退出並釋放資源pthread_join()
所需標頭檔#include <pthread.h>
函數原型int pthread_join ((pthread_t th, void **thread_return))
函數傳入值
th:等待線程的標識符
thread_return:使用者定義的指標,用來儲存被等待線程的傳回值(不為NULL時)
函數傳回值 成功:0 出錯:-1
代碼舉例
1. #include<pthread.h>
2. #include<stdio.h>
3. #include<errno.h>
4.
5. /*線程1*/
6. void thread1()
7. {
8. int i=0;
9.
10. while(1)
11. {
12. printf("thread1:%d\n",i);
13. if(i>3)
14. pthread_exit(0);
15. i++;
16. sleep(1);
17. }
18. }
19.
20. /*線程2*/
21. void thread2()
22. {
23. int i=0;
24.
25. while(1)
26. {
27. printf("thread2:%d\n",i);
28. if(i>5)
29. pthread_exit(0);
30. i++;
31. sleep(1);
32. }
33. }
34.
35. int main()
36. {
37. pthread_t t1,t2;
38.
39. /*建立線程*/
40. pthread_create(&t1,NULL,(void *)thread1,NULL);
41. pthread_create(&t2,NULL,(void *)thread2,NULL);
42. /*等待線程退出*/
43. pthread_join(t1,NULL);
44. pthread_join(t2,NULL);
45. return 0;
46. }
3同步與互斥
<1>互斥鎖
互斥鎖的操作主要包括以下幾個步驟。
• 互斥鎖初始化:pthread_mutex_init
• 互斥鎖上鎖:pthread_mutex_lock
• 互斥鎖判斷上鎖:pthread_mutex_trylock
• 互斥鎖接鎖:pthread_mutex_unlock
• 消除互斥鎖:pthread_mutex_destroy
1. #include<pthread.h>
2. #include<stdio.h>
3. #include<errno.h>
4.
5. int i=0;/*共用變數*/
6. pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;/*互斥鎖*/
7.
8. void thread1()
9. {
10. int ret;
11. while(1)
12. {
13.
14.
15. ret=pthread_mutex_trylock(&mutex);/*判斷上鎖*/
16.
17. if(ret!=EBUSY)
18. {
19. pthread_mutex_lock(&mutex);/*上鎖*/
20. printf("This is thread1:%d\n",i);
21. i++;
22. pthread_mutex_unlock(&mutex);/*解鎖*/
23. }
24. sleep(1);
25. }
26. }
27.
28. void thread2()
29. {int ret;
30. while(1)
31. {
32.
33. ret=pthread_mutex_trylock(&mutex);
34. if(ret!=EBUSY)
35. {
36. pthread_mutex_lock(&mutex);
37. printf("This is thread2:%d\n",i);
38. i++;
39. pthread_mutex_unlock(&mutex);
40. }
41. sleep(1);
42. }
43. }
44. int main()
45. {
46. pthread_t t1,t2;
47. pthread_mutex_init(&mutex,NULL);
48. pthread_create(&t1,NULL,(void *)thread1,NULL);
49. pthread_create(&t2,NULL,(void *)thread2,NULL);
50.
51. pthread_join(t1,NULL);
52. pthread_join(t2,NULL);
53.
54. pthread_mutex_destroy(&mutex);
55. return 0;
56. }
<2>訊號量
未進行同步處理的兩個線程
1. #include<pthread.h>
2. #include<stdio.h>
3. #include<errno.h>
4.
5. int i=0;
6. void thread1()
7. {
8.
9. while(1)
10. {
11. printf("This is thread1:%d\n",i);
12. i++;
13. sleep(1);
14. }
15. }
16.
17.
18. void thread2()
19. {
20.
21. while(1)
22. {
23. printf("This is thread2:%d\n",i);
24. i++;
25. sleep(1);
26. }
27. }
28.
29. int main()
30. {
31. pthread_t t1,t2;
32.
33. pthread_create(&t1,NULL,(void *)thread1,NULL);
34. pthread_create(&t2,NULL,(void *)thread2,NULL);
35.
36. pthread_join(t1,NULL);
37. pthread_join(t2,NULL);
38.
39. return 0;
40. }
執行結果如下:
This is thread1:0
This is thread2:1
This is thread2:2
This is thread1:3
This is thread2:4
This is thread1:4
This is thread2:6
This is thread1:7
......
可以看出:
1.線程2的執行並非必須線上程1之後,如果要求線程2必須線上程1之後執行,稱為同步
2.線程1和線程2可能對共用變數i的同時進行讀取,如果要求每次只有一個線程讀取i,成為互斥
訊號量的使用
•sem_init用於建立一個訊號量,並能初始化它的值。
•sem_wait和sem_trywait相當於P操作,它們都能將訊號量的值減一,兩者的區別在於若訊號量小於零時, sem_wait將會阻塞進程,而sem_trywait則會立即返回。
•sem_post相當於V操作,它將訊號量的值加一同時發出訊號喚醒等待的進程。
•sem_getvalue用於得到訊號量的值。
•sem_destroy用於刪除訊號量
代碼
1. #include<pthread.h>
2. #include<stdio.h>
3. #include<errno.h>
4. #include <semaphore.h>
5.
6.
7. int i=0;
8. sem_t sem1,sem2;
9.
10.
11. void thread1()
12. {
13.
14. while(1)
15. {
16. sem_wait(&sem1);
17. printf("This is thread1:%d\n",i);
18. i++;
19. sleep(3);/*線程1休眠3s,以便觀察線程2在輸出3s後才會執行*/
20. sem_post(&sem2);
21.
22. }
23. }
24.
25.
26. void thread2()
27. {
28.
29. while(1)
30. {
31. sem_wait(&sem2);
32. printf("This is thread2:%d\n",i);
33. i++;
34. sem_post(&sem1);
35. sleep(1);
36. }
37. }
38.
39. int main()
40. {
41. pthread_t t1,t2;
42.
43.
44.
45. sem_init(&sem1,0,1);/*初始化訊號量sem1*/
46. sem_init(&sem2,0,0);
47.
48. pthread_create(&t1,NULL,(void *)thread1,NULL);
49. pthread_create(&t2,NULL,(void *)thread2,NULL);
50.
51. pthread_join(t1,NULL);
52. pthread_join(t2,NULL);
53.
54. return 0;
55. }
1. #include<pthread.h>
2. #include<stdio.h>
3. #include<errno.h>
4. #include <semaphore.h>
5.
6.
7. int i=0;
8. sem_t sem;
9.
10.
11. void thread1()
12. {
13.
14. while(1)
15. {
16. sem_wait(&sem);
17. printf("This is thread1:%d\n",i);
18. i++;
19. sleep(3);/*線程1休眠3s,以便觀察線程2在輸出3s後才會執行*/
20. sem_post(&sem);
21.
22. }
23. }
24.
25.
26. void thread2()
27. {
28.
29. while(1)
30. {
31. sem_wait(&sem);
32. printf("This is thread2:%d\n",i);
33. i++;
34. sem_post(&sem);
35. sleep(1);
36. }
37. }
38.
39. int main()
40. {
41. pthread_t t1,t2;
42.
43.
44.
45. sem_init(&sem,0,1);/*初始化訊號量sem*/
46.
47. pthread_create(&t1,NULL,(void *)thread1,NULL);
48. pthread_create(&t2,NULL,(void *)thread2,NULL);
49.
50. pthread_join(t1,NULL);
51. pthread_join(t2,NULL);
52.
53. return 0;
54. }