Linux——线程使用及互斥量
線程的基本操作
概念
線程是程序中的一個執(zhí)行路線。每個程序當(dāng)中至少有一個線程。
程序在執(zhí)行的過程中是逐條執(zhí)行的,按照代碼的邏輯一次向下執(zhí)行,所以無法同時完成兩條指令,故而引進了線程,舉個很簡單的例子,如果同時進行兩個死循環(huán),用單線程的話只能進行一個死循環(huán),另一個死循環(huán)永遠也不會執(zhí)行,故而用多線程就可以解決這個問題。在學(xué)習(xí)網(wǎng)絡(luò)cs模型時更能體現(xiàn)線程的作用,因為你需要在發(fā)送數(shù)據(jù)的同時接收數(shù)據(jù)。
創(chuàng)建線程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);參數(shù)thread:返回線程IDattr:設(shè)置線程的屬性,attr為NULL表示使用默認(rèn)屬性start_routine:是個函數(shù)地址,線程啟動后要執(zhí)行的函數(shù)arg:傳給線程啟動函數(shù)的參數(shù)返回值:成功返回0;失敗返回錯誤碼獲取線程ID
pthread_t pthread_self(void)返回值返回調(diào)用該函數(shù)的線程的ID線程終止
void pthread_exit(void *value_ptr); 參數(shù)value_ptr:value_ptr不要指向一個局部變量。 該函數(shù)無返回值,跟進程一樣,線程結(jié)束的時候無法返回到它的調(diào)用者(自身)int pthread_cancel(pthread_t thread); 參數(shù)thread:線程ID 返回值:成功返回0;失敗返回錯誤碼線程等待
int pthread_join(pthread_t thread, void **value_ptr); 參數(shù)thread:線程IDvalue_ptr:它指向一個指針,后者指向線程的返回值 返回值:成功返回0;失敗返回錯誤碼為何要線程等待?線程退出時,其占有的空間資源并不會釋放掉,在次創(chuàng)建一個線程時該空間資源并不會被再次利用,也就是說會造成內(nèi)存泄漏,故而需要線程等待。其中線程等待函數(shù)中的參數(shù)value_ptr指向線程ID為thread的線程返回值。如果thread線程被別的線程調(diào)用pthread_ cancel異常終掉,value_ ptr所指向的單元里存放的是常數(shù)PTHREAD_ CANCELED;如果thread線程是自己調(diào)用pthread_exit終止的,value_ptr所指向的單元存放的是傳給pthread_exit的參數(shù)。
線程分離
int pthread_detach(pthread_t thread); 參數(shù)thread:線程ID 返回值:成功返回0,錯誤返回錯誤號線程分離與線程等待很相似,他們都能釋放掉已結(jié)束線程占用的空間資源,但線程分離不關(guān)心線程退出的返回值,只要線程退出,就自動釋放線程資源。
編譯指令
gcc 123.c -o out -lpthread 注:編譯多線程的程序一定要加上 -lpthread示例:
#include<pthread.h> #include<stdio.h> #include<unistd.h> void *fun(void *num) {int i=0;for(;i<30;i++){printf("a");if(i==25){pthread_exit(NULL);//輸出25個a后線程終止}usleep(1);//延時1us} }int main() {pthread_t ptid;if(pthread_create(&ptid,NULL,fun,NULL)!=0)//創(chuàng)建線程{return 0;}int i=0;for(;i<10;i++){if(i%2==0){printf("b");}usleep(2);//延時2us}printf("\n");pthread_join(ptid,NULL);線程等待return 0; }結(jié)果
主線程在執(zhí)行5個b后,輸出結(jié)束,此時等待子線程結(jié)束,即第二行結(jié)果顯示,至于第一行為什么a、b都有輸出,是因為線程在執(zhí)行時是同時進行的,主線程輸出一個b后睡眠2us,在這段時間子線程開始輸出a,因為子線程也有1us睡眠,限制其執(zhí)行速度,當(dāng)主線程的2us時間到后,又開始主線程輸出b。
線程互斥
我們先看看幾個概念:
臨界資源:多線程執(zhí)行流共享的資源就叫做臨界資源 臨界區(qū):每個線程內(nèi)部,訪問臨界資源的代碼,就叫做臨界區(qū) 互斥:任何時刻,互斥保證有且只有一個執(zhí)行流進入臨界區(qū),訪問臨界資源,通常對臨界資源起保護作 用 原子性:不會被任何調(diào)度機制打斷的操作,該操作只有兩態(tài),要么完成,要么未完成那到底什么是線程互斥呢?不要著急,我們先看看下面這個搶票的例子:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <sched.h>int ticket = 100;//共有100張票void *route(void *arg) {char *id=(char *)arg;while(1){if(ticket>0){usleep(1000);printf("%s sells ticket:%d\n",id,ticket);ticket--;//搶到票就減1}else{break; }} } int main() {pthread_t t1,t2,t3,t4;pthread_create(&t1,NULL,route,(void *)"thread 1");pthread_create(&t2,NULL,route,(void *)"thread 2");pthread_create(&t3,NULL,route,(void *)"thread 3");pthread_create(&t4,NULL,route,(void *)"thread 4");pthread_join(t1,NULL);pthread_join(t2,NULL);pthread_join(t3,NULL);pthread_join(t4,NULL);return 0;}結(jié)果
結(jié)果讓人感到意外,怎么會有負(fù)數(shù)呢?因為線程是同時進行的,當(dāng)進行到票數(shù)為1的時候,此時部分線程已經(jīng)經(jīng)過了**if(ticket>0)**的判斷,其中有一個線程的執(zhí)行速度比較快,他搶先拿到了最后的一張票,此時票數(shù)為0,因為此時并不止這一個線程經(jīng)過了判斷,他們也能強到一張票,故而出現(xiàn)負(fù)數(shù)。原理圖如下:
為避免上述現(xiàn)象的出現(xiàn),引進了互斥量mutex
互斥量初始化
靜態(tài)分配 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;動態(tài)分配 int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);參數(shù):mutex:要初始化的互斥量attr:NULL互斥量加鎖與解鎖
加鎖: int pthread_mutex_lock(pthread_mutex_t *mutex);解鎖: int pthread_mutex_unlock(pthread_mutex_t *mutex); 注:加鎖后一定要記得解鎖二者的參數(shù)相同,都是指初始化后的互斥量互斥量銷毀
int pthread_mutex_destroy(pthread_mutex_t *mutex); 參數(shù):需要銷毀的互斥量 注:靜態(tài)分配的互斥量不需要銷毀,已經(jīng)枷鎖的互斥量不能銷毀使用方法
改進后代碼
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include <sched.h>int ticket = 100;//票 pthread_mutex_t mutex;//定義互斥量void *route(void *arg) {char *id=(char *)arg;while(1){pthread_mutex_lock(&mutex);//加鎖if(ticket>0){printf("%s sells ticket:%d\n",id,ticket);ticket--;pthread_mutex_unlock(&mutex);//解鎖}else{pthread_mutex_unlock(&mutex);//解鎖break;}usleep(2);} } int main() {pthread_t t1,t2,t3,t4;pthread_mutex_init(&mutex,NULL);//初始化互斥量pthread_create(&t1,NULL,route,(void *)"thread 1");pthread_create(&t2,NULL,route,(void *)"thread 2");pthread_create(&t3,NULL,route,(void *)"thread 3");pthread_create(&t4,NULL,route,(void *)"thread 4");pthread_join(t1,NULL);pthread_join(t2,NULL);pthread_join(t3,NULL);pthread_join(t4,NULL);pthread_mutex_destroy(&mutex);//互斥量銷毀return 0;}結(jié)果
總結(jié)
以上是生活随笔為你收集整理的Linux——线程使用及互斥量的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 局域网在线监控设备扫描工具V1.0软件说
- 下一篇: zoj 1074 To the MAX