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 |
代碼舉例
- #include<pthread.h>
- #include<stdio.h>
- #include<errno.h>
- /*線程1*/
- void thread1()
- {
- int i=0;
- while(1)
- {
- printf("thread1:%d\n",i);
- if(i>3)
- pthread_exit(0);
- i++;
- sleep(1);
- }
- }
- /*線程2*/
- void thread2()
- {
- int i=0;
- while(1)
- {
- printf("thread2:%d\n",i);
- if(i>5)
- pthread_exit(0);
- i++;
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- /*創建線程*/
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- /*等待線程退出*/
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- return 0;
- }
3同步與互斥
<1>互斥鎖
互斥鎖的操作主要包括以下幾個步驟。
· 互斥鎖初始化:pthread_mutex_init
· 互斥鎖上鎖:pthread_mutex_lock
· 互斥鎖判斷上鎖:pthread_mutex_trylock
· 互斥鎖接鎖:pthread_mutex_unlock
· 消除互斥鎖:pthread_mutex_destroy
- #include<pthread.h>
- #include<stdio.h>
- #include<errno.h>
- int i=0;/*共享變量*/
- pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;/*互斥鎖*/
- void thread1()
- {
- int ret;
- while(1)
- {
- ret=pthread_mutex_trylock(&mutex);/*判斷上鎖*/
- if(ret!=EBUSY)
- {
- pthread_mutex_lock(&mutex);/*上鎖*/
- printf("This is thread1:%d\n",i);
- i++;
- pthread_mutex_unlock(&mutex);/*解鎖*/
- }
- sleep(1);
- }
- }
- void thread2()
- {int ret;
- while(1)
- {
- ret=pthread_mutex_trylock(&mutex);
- if(ret!=EBUSY)
- {
- pthread_mutex_lock(&mutex);
- printf("This is thread2:%d\n",i);
- i++;
- pthread_mutex_unlock(&mutex);
- }
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- pthread_mutex_init(&mutex,NULL);
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- pthread_mutex_destroy(&mutex);
- return 0;
- }
<2>信號量
未進行同步處理的兩個線程
- #include<pthread.h>
- #include<stdio.h>
- #include<errno.h>
- int i=0;
- void thread1()
- {
- while(1)
- {
- printf("This is thread1:%d\n",i);
- i++;
- sleep(1);
- }
- }
- void thread2()
- {
- while(1)
- {
- printf("This is thread2:%d\n",i);
- i++;
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- 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用於刪除信號量
代碼
- #include<pthread.h>
- #include<stdio.h>
- #include<errno.h>
- #include <semaphore.h>
- int i=0;
- sem_t sem1,sem2;
- void thread1()
- {
- while(1)
- {
- sem_wait(&sem1);
- printf("This is thread1:%d\n",i);
- i++;
- sleep(3);/*線程1休眠3s,以便觀察線程2在輸出3s後纔會執行*/
- sem_post(&sem2);
- }
- }
- void thread2()
- {
- while(1)
- {
- sem_wait(&sem2);
- printf("This is thread2:%d\n",i);
- i++;
- sem_post(&sem1);
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- sem_init(&sem1,0,1);/*初始化信號量sem1*/
- sem_init(&sem2,0,0);
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- return 0;
- }
- #include<pthread.h>
- #include<stdio.h>
- #include<errno.h>
- #include <semaphore.h>
- int i=0;
- sem_t sem;
- void thread1()
- {
- while(1)
- {
- sem_wait(&sem);
- printf("This is thread1:%d\n",i);
- i++;
- sleep(3);/*線程1休眠3s,以便觀察線程2在輸出3s後纔會執行*/
- sem_post(&sem);
- }
- }
- void thread2()
- {
- while(1)
- {
- sem_wait(&sem);
- printf("This is thread2:%d\n",i);
- i++;
- sem_post(&sem);
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- sem_init(&sem,0,1);/*初始化信號量sem*/
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- return 0;
- }
A 1 讀寫鎖
~讀加鎖狀態,若試圖以讀模式加鎖,則獲得訪問權,若試圖以寫模式加鎖,則阻塞
- int i=0;/*共享變量*/
- pthread_rwlock_t rwlock;/*互斥鎖*/
- void thread1()
- {
- while(1)
- {
- pthread_rwlock_rdlock(&rwlock);/*讀加鎖*/
- printf("This is thread1:%d\n",i);
- i++;
- pthread_rwlock_unlock(&rwlock);/*解鎖*/
- sleep(1);
- }
- }
- void thread2()
- {
- while(1)
- {
- pthread_rwlock_rdlock(&rwlock);
- printf("This is thread2:%d\n",i);
- i++;
- pthread_rwlock_unlock(&rwlock);
- sleep(1);
- }
- }
- int main()
- {
- pthread_t t1,t2;
- pthread_rwlock_init(&rwlock,NULL); /*初始化*/
- pthread_create(&t1,NULL,(void *)thread1,NULL);
- pthread_create(&t2,NULL,(void *)thread2,NULL);
- pthread_join(t1,NULL);
- pthread_join(t2,NULL);
- pthread_rwlock_destroy(&rwlock); /*銷燬*/
- 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釋放鎖。
~寫加鎖狀態,若試圖加鎖,則線程將阻塞,直至釋放鎖