Linux線程及同步

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.     int i=0; 
  8.      
  9.         while(1) 
  10.         { 
  11.      printf("thread1:%d\n",i); 
  12.      if(i>3) 
  13.         pthread_exit(0); 
  14.      i++; 
  15.      sleep(1); 
  16.     } 
  17.  
  18. /*線程2*/ 
  19. void thread2() 
  20.     int i=0; 
  21.      
  22.         while(1) 
  23.         { 
  24.      printf("thread2:%d\n",i); 
  25.      if(i>5) 
  26.         pthread_exit(0); 
  27.      i++; 
  28.      sleep(1); 
  29.     } 
  30.  
  31. int main() 
  32.  pthread_t t1,t2; 
  33.  
  34. /*創建線程*/ 
  35.  pthread_create(&t1,NULL,(void *)thread1,NULL); 
  36.  pthread_create(&t2,NULL,(void *)thread2,NULL); 
  37.  /*等待線程退出*/ 
  38.  pthread_join(t1,NULL); 
  39.  pthread_join(t2,NULL); 
  40.  return 0; 

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.     int ret; 
  10.     while(1) 
  11.     { 
  12.          
  13.       
  14.      ret=pthread_mutex_trylock(&mutex);/*判斷上鎖*/ 
  15.       
  16.      if(ret!=EBUSY) 
  17.         { 
  18.         pthread_mutex_lock(&mutex);/*上鎖*/ 
  19.         printf("This is thread1:%d\n",i); 
  20.        i++; 
  21.       pthread_mutex_unlock(&mutex);/*解鎖*/ 
  22.      } 
  23.      sleep(1); 
  24.     } 
  25.  
  26. void thread2() 
  27. {int ret; 
  28.     while(1) 
  29.     { 
  30.       
  31.      ret=pthread_mutex_trylock(&mutex); 
  32.      if(ret!=EBUSY) 
  33.         { 
  34.         pthread_mutex_lock(&mutex); 
  35.         printf("This is thread2:%d\n",i); 
  36.        i++; 
  37.       pthread_mutex_unlock(&mutex); 
  38.      } 
  39.      sleep(1); 
  40.     } 
  41. int main() 
  42.  pthread_t t1,t2; 
  43.  pthread_mutex_init(&mutex,NULL); 
  44.  pthread_create(&t1,NULL,(void *)thread1,NULL); 
  45.  pthread_create(&t2,NULL,(void *)thread2,NULL); 
  46.   
  47.  pthread_join(t1,NULL); 
  48.  pthread_join(t2,NULL); 
  49.   
  50.  pthread_mutex_destroy(&mutex); 
  51.  return 0; 

<2>信號量

未進行同步處理的兩個線程

 

  1. #include<pthread.h> 
  2. #include<stdio.h> 
  3. #include<errno.h> 
  4.  
  5. int i=0; 
  6. void thread1() 
  7.      
  8.     while(1) 
  9.     {   
  10.         printf("This is thread1:%d\n",i); 
  11.       i++; 
  12.       sleep(1); 
  13.   } 
  14.  
  15.  
  16. void thread2() 
  17.  
  18.     while(1) 
  19.     {   
  20.         printf("This is thread2:%d\n",i); 
  21.       i++; 
  22.       sleep(1); 
  23.   } 
  24.  
  25. int main() 
  26.  pthread_t t1,t2; 
  27.  
  28.  pthread_create(&t1,NULL,(void *)thread1,NULL); 
  29.  pthread_create(&t2,NULL,(void *)thread2,NULL); 
  30.   
  31.  pthread_join(t1,NULL); 
  32.  pthread_join(t2,NULL); 
  33.   
  34.  return 0; 

執行結果如下:

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.     while(1) 
  14.     {   
  15.           sem_wait(&sem1); 
  16.         printf("This is thread1:%d\n",i); 
  17.       i++; 
  18.       sleep(3);/*線程1休眠3s,以便觀察線程2在輸出3s後纔會執行*/ 
  19.       sem_post(&sem2); 
  20.        
  21.   } 
  22.  
  23.  
  24. void thread2() 
  25.  
  26.     while(1) 
  27.     {   
  28.         sem_wait(&sem2); 
  29.         printf("This is thread2:%d\n",i); 
  30.       i++; 
  31.       sem_post(&sem1); 
  32.       sleep(1); 
  33.   } 
  34.  
  35. int main() 
  36.  pthread_t t1,t2; 
  37.  
  38.   
  39.  
  40.  sem_init(&sem1,0,1);/*初始化信號量sem1*/ 
  41.  sem_init(&sem2,0,0); 
  42.  
  43.  pthread_create(&t1,NULL,(void *)thread1,NULL); 
  44.  pthread_create(&t2,NULL,(void *)thread2,NULL); 
  45.   
  46.  pthread_join(t1,NULL); 
  47.  pthread_join(t2,NULL); 
  48.   
  49.  return 0; 

 

 

  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.     while(1) 
  14.     {   
  15.           sem_wait(&sem); 
  16.         printf("This is thread1:%d\n",i); 
  17.       i++; 
  18.       sleep(3);/*線程1休眠3s,以便觀察線程2在輸出3s後纔會執行*/ 
  19.       sem_post(&sem); 
  20.        
  21.   } 
  22.  
  23.  
  24. void thread2() 
  25.  
  26.     while(1) 
  27.     {   
  28.         sem_wait(&sem); 
  29.         printf("This is thread2:%d\n",i); 
  30.       i++; 
  31.       sem_post(&sem); 
  32.       sleep(1); 
  33.   } 
  34.  
  35. int main() 
  36.  pthread_t t1,t2; 
  37.  
  38.   
  39.  
  40.  sem_init(&sem,0,1);/*初始化信號量sem*/ 
  41.  
  42.  pthread_create(&t1,NULL,(void *)thread1,NULL); 
  43.  pthread_create(&t2,NULL,(void *)thread2,NULL); 
  44.   
  45.  pthread_join(t1,NULL); 
  46.  pthread_join(t2,NULL); 
  47.   
  48.  return 0; 

 

A 1 讀寫鎖

~讀加鎖狀態,若試圖以讀模式加鎖,則獲得訪問權,若試圖以寫模式加鎖,則阻塞

 

  1. int i=0;/*共享變量*/  
  2. pthread_rwlock_t rwlock;/*互斥鎖*/  
  3.   
  4. void thread1()  
  5. {   
  6.     while(1)  
  7.     { 
  8.        pthread_rwlock_rdlock(&rwlock);/*讀加鎖*/  
  9.        printf("This is thread1:%d\n",i);  
  10.        i++;  
  11.        pthread_rwlock_unlock(&rwlock);/*解鎖*/  
  12.      sleep(1);  
  13.     }  
  14. }  
  15.   
  16. void thread2()  
  17.     while(1)  
  18.     {  
  19.         pthread_rwlock_rdlock(&rwlock);  
  20.         printf("This is thread2:%d\n",i);  
  21.        i++;  
  22.       pthread_rwlock_unlock(&rwlock);  
  23.       
  24.      sleep(1);  
  25.     }  
  26. }  
  27. int main()  
  28. {  
  29.  pthread_t t1,t2;  
  30.  pthread_rwlock_init(&rwlock,NULL);  /*初始化*/
  31.  pthread_create(&t1,NULL,(void *)thread1,NULL);  
  32.  pthread_create(&t2,NULL,(void *)thread2,NULL);  
  33.    
  34.  pthread_join(t1,NULL);  
  35.  pthread_join(t2,NULL);  
  36.    
  37.  pthread_rwlock_destroy(&rwlock);  /*銷燬*/
  38.  return 0;  

結果:

This is thread2:0
This is thread1:0
This is thread2:2
This is thread1:2
This is thread2:4
This is thread1:4
This is thread2:6
This is thread1:6
This is thread2:8
This is thread1:9
可以看到 ,線程1以讀模式加鎖後,線程2以讀模式加鎖,未阻塞,可以訪問變量i,

當將線程2改爲寫模式加鎖後,結果爲:

This is thread2:0
This is thread1:1
This is thread2:2
This is thread1:3
This is thread2:4
This is thread1:5
This is thread1:6
This is thread2:7
This is thread1:8
This is thread2:9
此時,線程2會處於阻塞,直至線程1釋放鎖。

~寫加鎖狀態,若試圖加鎖,則線程將阻塞,直至釋放鎖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章