Linux-C-day-6-線程

線程基礎(chǔ)

線程是進程的一個執(zhí)行單元躯护,執(zhí)行一段程序片段庞钢,線程共享全局變量;線程的查看可以使用命令或者文件來進行查看;命令:ps -T -p <pid> -T:表示用于開啟線程查看室谚;top -H -p <pid> -H 用于開啟線程查看;還可以通過htop 使用F2開啟樹狀圖查看選項溉旋,或者開啟顯示自定義線程名選項救军;F10用于退出設(shè)置;文件:/proc/PID/task 線程的名字默認和進程相同毒嫡;/proc/PID/task/comm線程名稱癌蚁;

線程的相關(guān)函數(shù)
線程標識

pthread_t pthread_self(void);返回值是當前線程ID兜畸,可以使用%lu打印線程pid的值努释;設(shè)置線程名稱:int prctl(int option,unsigned long arg2);PR_GET_NAME用于獲得當前線程的名字咬摇,PR_SET_NAME伐蒂,用于設(shè)置當前線程的名字;arg2:線程名稱最大長度為15個字節(jié)肛鹏,并且應該以'\0'結(jié)尾逸邦,一共16個字符;返回值:0表示成功非0表示出錯在扰;
thread01.c

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/prctl.h>

int main(){
    printf("PID:%d,TID:%lu\n",getpid(),pthread_self());
    char name[16] = {0};
    prctl(PR_SET_NAME,"test");
    prctl(PR_GET_NAME,name);
    printf("TNAME:%s\n",name);
}

thread02.c

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/prctl.h>

int info(){
    printf("PID:%d,TID:%lu",getpid(),pthread_self());
    char name[16] = {0};
    prctl(PR_GET_NAME,name);
    printf("TNAME:%s\n",name);
}

void* method(void* arg){
    info();
}

int main(){
    info();
    pthread_t tid;
    pthread_create(&tid,NULL,method,NULL);
    printf("new tid:%lu\n",tid);
    sleep(1);
}
線程創(chuàng)建

int pthread_create(pthread_t *tidp,pthread_attr_t *attr,void (start_rtn)(void),void *arg)缕减;tidp:線程ID指針;
?attr:線程屬性:綁定:pthread_attr_setscope(pthread_attr_t *attr, int scope)芒珠;scope:PTHREAD_SCOPE_PROCESS:表示不進行綁定桥狡,這個是默認的選項;PTHREAD_SCOPE_SYSTEM表示綁定輕進程(LWP)/內(nèi)核線程;
?分離:pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)裹芝;detachstate:PTHREAD_CREATE_DETACHED:表示分離線程部逮;PTHREAD_CREATE_JOINABLE表示非分離線程;
?線程使用的是缺省的堆棧嫂易,線程的優(yōu)先級和父進程同級別兄朋;
線程的ID指針返回值是void類型的指針函數(shù);arg:表示的是start_rtn的形式參數(shù)炬搭;返回值0表示成功蜈漓,非0表示出錯;

線程消亡

線程的消亡分為正常終止和線程取消兩種情況宫盔;線程正常終止:對于子線程來說線程處理函數(shù)return 返回一個返回值融虽,線程可以終止,線程終止還可以調(diào)用pthread_exit(void* retval);來進行處理灼芭,retval:表示函數(shù)的返回指針有额,只要pthread_join中的第二個參數(shù)retval不是NULL,這個值江北傳遞給retval彼绷,如果用在線程回調(diào)函數(shù)中巍佑,將返回線程數(shù)據(jù);

對于主線程:線程合并:int pthread_join(pthread_t tid, void **retval)寄悯;tid:被等待的線程標識符萤衰,retval一個用戶定義的指針,它可以用來存儲被等待線程的返回值猜旬,返回值:0表示成功脆栋,非0表示錯誤碼;當進行線程合并時洒擦,可以由其他線程來終止椿争,并且回收資源;
pthread_join.c:線程取消函數(shù)

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/prctl.h>

int info(){
    printf("PID:%d,TID:%lu",getpid(),pthread_self());
    char name[16] = {0};
    prctl(PR_GET_NAME,name);
    printf("TNAME:%s\n",name);
}

void* method(void* arg){
    sleep(5);
    info();
}

int main(){
    info();
    pthread_t tid;
    pthread_create(&tid,NULL,method,NULL);
    printf("new tid:%lu\n",tid);
    //sleep(1);
    pthread_join(tid,NULL);
}

主線程終止的另一種方式是線程分離int pthread_detach(ppthread_t tid)熟嫩;tid:表示要釋放線程的標識符秦踪,返回值0表示成功,非0表示錯誤碼掸茅;但是這樣是不能被其他線程終止的椅邓,存儲在它終止時,有系統(tǒng)自動的回收釋放昧狮;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

線程取消:取消點取消景馁,如果線程接收到取消信號,到達指定位置才能能取消陵且,取消點取消分為手動:void pthread_testcancle(void)裁僧;自動:通過引起阻塞的系統(tǒng)調(diào)用來取消;
?線程取消:發(fā)送取消信號:int pthread_cancel(pthread_t pthread)慕购,需要注意的是:發(fā)送成功并不一定意味著thread線程就會終止聊疲,發(fā)送CANCEL指令后,使用pthread_join 函數(shù)沪悲,等待指定的線程完全退出以后获洲,在繼續(xù)執(zhí)行,否則容易產(chǎn)生段錯誤殿如;函數(shù)的返回值0表示成功贡珊,非0值表示失敗涉馁;
?設(shè)置當前線程的取消類型:int pthread_setcancelstate(int state门岔,int *oldstate);state:PTHREAD_CANCEL_ENABLE:線程取消啟用烤送;PTHREAD_CANCEL_DISABLE:表示線程取消禁用寒随;oldstate:表示線程之前的狀態(tài);
?設(shè)置當前線程的取消類型:int pthread_setcanceltype(int type,int *oldtype)帮坚;type:PTHREAD_CANCEL_DEFFERED:表示取消點取消妻往;PTHREAD_CANCEL_ASYNCHRONOUS:表示立即退出;oldstate:表示之前的取消類型试和;
?設(shè)置取消點:void pthread_testcanel(void)讯泣;
pthread_cancel.c

#include <stdio.h>
#include <pthread.h>

long count = 0;

void* default_func(void* arg){
    for(;;){
        pthread_testcancel();
        count++;
    }
}

void* disable_func(void* arg){
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    for(;;){
        pthread_testcancel();
        count++;
    }
}
void* force_func(void* arg){
    pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    for(;;){
        count++;
    }
}

void* disable_force_func(void* arg){
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
    for(;;){
        count++;
    }
}
void* watch(void* arg){
    for(;;){
        sleep(1);
        printf("count:%d\n",count);
    }
}

void* cancel(void* arg){
    sleep(5);
    pthread_t* ptid = arg;
    printf("cancel %lu\n",ptid[0]);
    pthread_cancel(ptid[0]);    
}

int main(int argc,char* argv[]){
    typedef void* (*Func)(void*); 
    Func funcs[3] = {default_func,watch,cancel}; 

    int c;
    while((c=getopt(argc,argv,"dp"))!=-1){
        switch(c){
            case 'd':
                funcs[0] = (funcs[0] == default_func?disable_func:disable_force_func);
                break;
            case 'p':
                funcs[0] = (funcs[0] == default_func?force_func:disable_force_func);
                break;
        }
    }

    pthread_t tids[3];
    int i=0;
    for(;i<3;i++){
        pthread_create(&tids[i],NULL,funcs[i],&tids);
        printf("create thread %lu\n",tids[i]);
    }
    for(i=0;i<3;i++){
        pthread_join(tids[i],NULL);
    }

}

發(fā)送信號:int pthread_kill(pthread_t tid, int sig)阅悍;tid:表示線程ID好渠,sig:信號晦墙,0表示保留信號,用于測試線程是否存在寡痰,信號為正數(shù)表示系統(tǒng)自定義信號或者系統(tǒng)自定義信號抗楔;返回值:0表示調(diào)用成功,ESRCH:表示線程不存在拦坠;EINVAL:表示信號不合法连躏;


設(shè)置線程并發(fā)度:并發(fā)度表示線程并發(fā)的數(shù)目,int pthread_setconcurrency(int level)贞滨;獲取線程并發(fā)度:int pthread_getconcurrency(void)入热;
?void pthread_cleanup_push(void (routine)(void),void *arg)拍棕;void pthread_cleanup_pop(int execute);execute通常為0勺良;關(guān)于線程的信息可以man 7 threads绰播;
?線程間通信使用全局變量的方式進行;

線程同步

信號量

信號量的創(chuàng)建:int sem_init(sem_t *sem,int pshared,unsigned int value)尚困;sem:表示信號量對象蠢箩;pshared:表示信號量的類型,0表示線程共享事甜,<0:表示進程共享谬泌;value:用于表示初始值;返回值0表示成功逻谦,-1表示失斦剖怠;


?銷毀:int sem_destory(sem_t *sem)邦马;sem:表示信號量對象潮峦;返回值0表示成功,-1表示失斢掠ぁ忱嘹;


等待:包括三種:阻塞等待,int sem_wait(sem_t *sem)耕渴;sem:標識信號量對象拘悦;返回值0表示成功,-1表示失敵髁场础米;非阻塞等待:int sem_trywait(sem_t *sem);sem:表示信號量對象添诉;返回值0表示成功屁桑,-1表示失敗栏赴;超時等待:int sem_timedwait(sem_t *sem蘑斧,struct timespec *abstime);sem:表示信號量對象须眷;abstime:表示等待時間竖瘾;-1表示等待超時,0表示成功花颗;
?觸發(fā):sem:信號量對象捕传;0:表示成功;-1:表示成功扩劝;


互斥量

互斥量和信號量的區(qū)別:
?1庸论、互斥量用于線程的互斥职辅,信號用于線程的同步互斥:是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排他性聂示,但是滬指無法限制資源訪問者對其資源的訪問順序罐农,也就是訪問是無序的;同步:是指在互斥的基礎(chǔ)上催什,通過其它機制實現(xiàn)訪問者對資源的有序訪問,在大多數(shù)情況下宰睡,同步已經(jīng)實現(xiàn)了互斥蒲凶,特別是所有寫入資源的情況 都是互斥的,少數(shù)情況是指可以允許多個訪問者同時訪問資源拆内;
?2旋圆、互斥量值只能是0或者1,信號量值可以作為非負整數(shù)麸恍,也就是說灵巧,一個互斥量只能用于一個資源的互斥訪問,它不能解決多個資源的多線程互斥問題抹沪,信號量可以實現(xiàn)多個同類資源的多線程互斥和同步刻肄。當信號量為單值信號量時,也可以完成一個資源的互斥訪問融欧;
?3敏弃、互斥量的加鎖和解鎖必須有同一個線程使用,信號量可以由一個線程釋放噪馏,另一個線程得到麦到;
?4、信號量可以允許多個線程進入臨界區(qū)欠肾,互斥體只能允許一個線程進入臨界區(qū)瓶颠;
?ATM取款,toilet刺桃;互斥量分為靜態(tài)分配互斥量粹淋,實現(xiàn)特點是簡單,pthread_mutex = PTHREAD_MUTEX_INITIAVIZER瑟慈;動態(tài)分配互斥量:特點是可以設(shè)置更多的選項廓啊;pthread_mutex_init(&mutex,NULL)或者pthread_mutex_destory(&mutex);
?互斥量的操作:加鎖:互斥鎖int pthread_mutex_lock(pthread_t *mutex)封豪;嘗試加鎖 int pthread_mutex_trylock(pthread_t *mutex)谴轮,mutex:表示的也是互斥鎖;解鎖:int pthread_mutex_unlock(pthread_t *mutex)吹埠,mutex同樣表示的是互斥鎖第步;
mutex01.c

#include <stdio.h>
#include <pthread.h>

void* func(void* arg){
    pthread_mutex_lock(arg);
    printf("enter func\n");
    sleep(1);
    printf("do something\n");
    sleep(1);
    printf("level func\n");
    pthread_mutex_unlock(arg);
}

int main(int argc,int argv[]){
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex,NULL);
    
    pthread_t tids[3];
    int i;
    for(i=0;i<3;i++){
        pthread_create(&tids[i],NULL,func,&mutex);
    }
    for(i=0;i<3;i++){
        pthread_join(tids[i],NULL);
    }
    pthread_mutex_destroy(&mutex);

}

mutex02.c

#include <stdio.h>
#include <pthread.h>

void* func(void* arg){
    pthread_cleanup_push(pthread_mutex_unlock,arg);

    pthread_mutex_lock(arg);
    printf("enter func\n");
    sleep(1);
    printf("do something\n");
    sleep(1);
    printf("level func\n");
    pthread_exit(0);

    pthread_cleanup_pop(0);
}

int main(int argc,int argv[]){
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex,NULL);
    
    pthread_t tids[3];
    int i;
    for(i=0;i<3;i++){
        pthread_create(&tids[i],NULL,func,&mutex);
    }
    for(i=0;i<3;i++){
        pthread_join(tids[i],NULL);
    }
    pthread_mutex_destroy(&mutex);

}
條件變量

線程掛起直到共享數(shù)據(jù)的某些條件得到滿足疮装;條件變量分為靜態(tài)分配條件變量,pthread_cond_t_cond = PTHREAD_COND_INITIALIZER特點是比較簡單粘都;動態(tài)分配靜態(tài)變量:特點是可以設(shè)置更多的選項廓推,pthread_cond_init(&cond,NULL);或者使用pthread_cond_destory(&cond)翩隧;
操作:
?條件等待:int pthrad_cond_wait(pthread_cond_t *cond樊展,pthread_mutex_t *mutex);cond:表示條件變量堆生;mutex:表示互斥鎖专缠;
?計時等待:int pthread_cond_timedwait(pthread_cond_t *cond,pthread_muex_t *mutex,const struct timespec *abstime);cond:表示條件變量淑仆;mutex:表示互斥鎖涝婉;abstime:表示等待時間;返回值:ETIMEDOUT:表示超時等待結(jié)束蔗怠;
激活操作:
?單個激活:int pthread_cond_signal(pthread_cond_t *cond)墩弯;cond:表示條件變量,返回值0表示成功寞射,正數(shù)表示錯誤碼渔工;
?全部激活: int pthread_cond_broadcast(pthread_cond_t *cond);cond:表示條件變量桥温,返回值0表示成功涨缚,正數(shù)表示錯誤碼;

線程讀寫鎖

讀取鎖是共享鎖策治,寫入鎖是獨占鎖脓魏;
?靜態(tài)分配讀寫鎖:pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER,特點是實現(xiàn)簡單;動態(tài)分配讀寫鎖:pthread_rwlock_init(&rwlock,NULL)通惫;pthread_rwlock_destory(&rwlock)茂翔;可以用于設(shè)置更多選項

關(guān)于鎖的操作

讀取鎖:加讀取鎖:int pthread_rwlock_rdlock(pthread_rwlock *rwlock),int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)履腋;加寫入鎖:int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)珊燎;int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);解鎖操作:int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)遵湖;

線程和進程的區(qū)別

接口對比:

getpid pthread_self 用于獲得控制流的ID
fork pthread_create 創(chuàng)建新的控制流
exit pthread_exit 退出已有的控制流
waitpid pthread_join 等待控制流并獲得結(jié)束代碼

1悔政、進程是資源分配和擁有的基本單位,線程是處理器調(diào)度的基本單位延旧;
2谋国、進程擁有獨立的地址空間,線程共性進程的地址空間迁沫;
3芦瘾、線程上下文切換比進程上下文切換要快得多捌蚊;
4、子進程崩潰不會影響其它子進程近弟,但是任何一個線程崩潰缅糟,整個程序都會崩潰;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末祷愉,一起剝皮案震驚了整個濱河市窗宦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌二鳄,老刑警劉巖赴涵,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異泥从,居然都是意外死亡,警方通過查閱死者的電腦和手機沪摄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門躯嫉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人杨拐,你說我怎么就攤上這事祈餐。” “怎么了哄陶?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵帆阳,是天一觀的道長。 經(jīng)常有香客問我屋吨,道長蜒谤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任至扰,我火速辦了婚禮鳍徽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘敢课。我一直安慰自己阶祭,他們只是感情好,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布直秆。 她就那樣靜靜地躺著濒募,像睡著了一般。 火紅的嫁衣襯著肌膚如雪圾结。 梳的紋絲不亂的頭發(fā)上瑰剃,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音筝野,去河邊找鬼培他。 笑死鹃两,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的舀凛。 我是一名探鬼主播俊扳,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼猛遍!你這毒婦竟也來了馋记?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤懊烤,失蹤者是張志新(化名)和其女友劉穎梯醒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腌紧,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡茸习,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了壁肋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片号胚。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖浸遗,靈堂內(nèi)的尸體忽然破棺而出猫胁,到底是詐尸還是另有隱情,我是刑警寧澤跛锌,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布弃秆,位于F島的核電站,受9級特大地震影響髓帽,放射性物質(zhì)發(fā)生泄漏菠赚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一郑藏、第九天 我趴在偏房一處隱蔽的房頂上張望锈至。 院中可真熱鬧,春花似錦译秦、人聲如沸峡捡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽们拙。三九已至,卻和暖如春阁吝,著一層夾襖步出監(jiān)牢的瞬間砚婆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留装盯,地道東北人坷虑。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像埂奈,于是被迫代替她去往敵國和親迄损。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)自:Youtherhttps://www.cnblogs.com/youtherhome/archive/201...
    njukay閱讀 1,616評論 0 52
  • linux線程同步 信號燈:與互斥鎖和條件變量的主要不同在于"燈"的概念账磺,燈亮則意味著資源可用芹敌,燈滅則意味著不可用...
    鮑陳飛閱讀 688評論 0 2
  • 一、線程的創(chuàng)建和調(diào)度 1.線程是程序執(zhí)行的某一條指令流的映像垮抗。 為了進一步減少處理機制的空轉(zhuǎn)時間氏捞,支持多處理器及減...
    穹藍奧義閱讀 1,112評論 2 5
  • 創(chuàng)建線程 C99新增restrict用于限定指針;該關(guān)鍵字用于告訴編譯器,所有修改該指針所指向的內(nèi)容的操作全部都是...
    Joe_HUST閱讀 920評論 0 0
  • 簡介 線程創(chuàng)建 線程屬性設(shè)置 線程參數(shù)傳遞 線程優(yōu)先級 線程的數(shù)據(jù)處理 線程的分離狀態(tài) 互斥鎖 信號量 一 線程創(chuàng)...
    第八區(qū)閱讀 8,563評論 1 6