亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 操作系統 > 正文

線程之線程終止

2024-06-28 13:28:24
字體:
來源:轉載
供稿:網友
線程之線程終止

如果進程中的任一線程調用了exit、_Exit或者_exit,那么整個進程就會終止。與此類似,如果信號的默認動作是終止進程,那么,把該信號發送到線程會終止整個進程。

單個線程可以通過下列三種方式退出,在不終止整個進程的情況下停止它的控制流。

(1)線程只是從啟動例程中返回,返回值是線程的退出碼。

(2)線程可以被同一進程中的其他線程取消。

(3)線程調用pthread_exit。

#include <pthread.h>void pthread_exit(void *rval_ptr);

rval_ptr是一個無類型指針,與傳給啟動例程的單個參數類似。進程中的其他線程可以通過調用pthread_join函數訪問到這個指針。

#include <pthread.h>int pthread_join(pthread_t thread, void **rval_ptr);返回值:若成功則返回0,否則返回錯誤編號

調用線程將一直阻塞,直到指定的線程調用pthread_exit、從啟動例程中返回或者被取消。如果線程只是從它的啟動例程返回,rval_ptr將包含返回碼。如果線程被取消,由rval_ptr指定的內存單元就置為PTHREAD_CANCELED。

可以通過調用pthread_join自動把線程置于分離狀態,這樣資源就可以恢復。如果線程已經處于分離狀態,pthread_join調用就會失敗,返回EINVAL。

如果對線程的返回值并不感興趣,可以把rval_ptr置為NULL。在這種情況下,調用pthread_join函數將等待指定的線程終止,但并不獲取線程的終止狀態。

實例

程序清單11-2說明了如何獲取已終止的線程的退出碼。

程序清單11-2 獲得線程退出狀態

#include "apue.h"#include <pthread.h>void *thr_fn1(void *arg){    PRintf("thread 1 returning/n");    return((void *)1);}void *thr_fn2(void *arg){    printf("thread 2 exiting/n");    pthread_exit((void *)2);}int main(void){    int         err;    pthread_t    tid1, tid2;    void        *tret;    err = pthread_create(&tid1, NULL, thr_fn1, NULL);    if(err != 0)        err_quit("can't create thread 1: %s/n", strerror(err));    err = pthread_create(&tid2, NULL, thr_fn2, NULL);    if(err != 0)        err_quit("can't create thread 2: %s/n", strerror(err));    err = pthread_join(tid1, &tret);    if(err != 0)        err_quit("can't join with thread 1: %s/n", strerror(err));    printf("thread 1 exit code %d/n", (int)tret);    err = pthread_join(tid2, &tret);    if(err != 0)        err_quit("can't join with thread 2: %s/n", strerror(err));    printf("thread 2 exit code %d/n", (int)tret);    exit(0);}

運行程序清單11-2中的程序,得到的結果是:

未命名

可以看出,當一個線程通過調用pthread_exit退出或者簡單地從啟動例程中返回時,進程中的其他線程可以通過調用pthread_join函數獲得該線程的退出狀態。

pthread_create和pthread_exit函數的無類型指針參數能傳遞的數值可以不止一個,該指針可以傳遞包含更復雜信息的結構的地址,但是注意這個結構所使用的內存在調用者完成調用以后必須仍然是有效的,否則就會出現無效或非法內存訪問。

實例

程序清單11-3中的程序給出了用自動變量(分配在棧上)作為pthread_exit的參數時出現的問題。

程序清單11-3 pthread_exit參數的不正確使用

#include "apue.h"#include <pthread.h>struct foo {    int a, b, c, d;};void printfoo(const char *s, const struct foo *fp){    printf(s);    printf("   structure at 0x%x/n", (unsigned)fp);    printf("   foo.a = %d/n", fp->a);    printf("   foo.b = %d/n", fp->b);    printf("   foo.c = %d/n", fp->c);    printf("   foo.d = %d/n", fp->d);}void *thr_fn1(void *arg){    struct foo foo = {1, 2, 3, 4};    printfoo("thread 1:/n", &foo);    pthread_exit((void *)&foo);    printfoo("thread 1:/n", &foo);}void *thr_fn2(void *arg){    printf("thread 2: ID is %d/n", pthread_self());    pthread_exit((void *)0);}intmain(void){    int         err;    pthread_t    tid1, tid2;    struct foo    *fp;        err = pthread_create(&tid1, NULL, thr_fn1, NULL);    if(err != 0)        err_quit("can't create thread 1: %s/n", strerror(err));    err = pthread_join(tid1, (void *)&fp);    if(err != 0)        err_quit("can't join with thread 1: %s/n", strerror(err));    sleep(1);//    printf("parent starting  second thread/n");        //    err = pthread_create(&tid2, NULL, thr_fn2, NULL);//    if(err != 0)//        err_quit("cant' create thread 2: %s/n", strerror(err));    sleep(1);    printfoo("parent: /n", fp);    exit(0);}

運行程序清單11-3中的程序得到:

情況一:把帶注釋的行去掉注釋也編譯進程序中時的運行結果:

未命名

情況二:帶注釋的行不包括在程序中時的運行結果:

未命名

可以看出,當主線程訪問這個結構時,結構的內容(在線tid1的棧上分配)已經改變。為了解決這個問題,可以使用全局結構,或者用malloc函數分配結構。

例如,若把struct foo foo = {1, 2, 3, 4}; 移到函數外,使其成為全局結構,則可得到如下結果:

未命名 

線程可以通過調用pthread_cancel函數來請求取消同一進程中的其他線程。

#include <pthread.h>int pthread_cancel(pthread_t tid);返回值:若成功則返回0,否則返回錯誤編號

在默認情況下,pthread_cancel函數會使得由tid標識的線程的行為表現為如同調用了參數為PTHREAD_CANCELED的pthread_exit函數,但是,線程可以選擇忽略取消方式或是控制取消方式。注意,pthread_cancel并不等待線程終止,它僅僅提出請求。

線程可以安排它退出時需要調用的函數,這與進程可以用atexit函數安排進程退出時需要調用的函數是類似的。這樣的函數稱為線程清理處理程序(thread cleanup handler)。線程可以建立多個清理處理程序。處理程序記錄在棧中,也就是說它們的執行順序與它們注冊時的順序相反。

#include <pthread.h>void pthread_cleanup_push(void (*rtn)(void *), void *arg);void pthread_cleanup_pop(int execute);

當線程執行以下動作時調用清理函數(調用參數為arg,清理函數rtn的調用順序是由pthread_cleanup_push函數來安排的):

  • 調用pthread_exit時。
  • 相應取消請求時。
  • 用非零execute參數調用pthread_cleanup_pop時。

如果execute參數置為0,清理函數將不被調用。無論哪種情況,pthread_cleanup_pop都將刪除上次pthread_cleanup_push調用建立的清理處理程序。

這些函數有一個限制,由于它們可以實現為宏,所以必須在與線程相同的作用域中以匹配對的形式使用,pthread_cleanup_push的宏定義可以包含字符{,在這種情況下對應的匹配字符}就要在pthread_cleanup_pop定義中出現。

實例

程序清單11-4顯示了如何使用線程清理處理程序。需要把pthread_cleanup_pop調用和pthread_cleanup_push調用匹配起來,否則,程序編譯可能通不過。

程序清單11-4 線程清理處理程序

#include "apue.h"#include <pthread.h>void cleanup(void *arg){    printf("cleanup: %s/n", (char *)arg);}void *thr_fn1(void *arg){    printf("thread 1 start/n");    pthread_cleanup_push(cleanup, "thread 1 first hanlder");        pthread_cleanup_push(cleanup, "thread 1 second handler");    printf("thread 1 push complete/n");    if(arg)        return((void *)1);    pthread_cleanup_pop(0);    pthread_cleanup_pop(0);    return((void *)1);}void *thr_fn2(void *arg){    printf("thread 2 start/n");    pthread_cleanup_push(cleanup, "thread 2 first handler");    pthread_cleanup_push(cleanup, "thread 2 second handler");    printf("thread 2 push complete/n");    if (arg)        pthread_exit((void *)2);    pthread_cleanup_pop(0);    pthread_cleanup_pop(0);    pthread_exit((void *)2);}intmain(void){    int        err;        pthread_t    tid1, tid2;    void        *tret;    err = pthread_create(&tid1, NULL, thr_fn1, (void *)1);    if(err != 0)        err_quit("can't create thread 1: %s/n", strerror(err));    err = pthread_create(&tid2, NULL, thr_fn2, (void *)1);    if(err != 0)        err_quit("can't create thread 2: %s/n", strerror(err));    err = pthread_join(tid1, &tret);    if(err != 0)        err_quit("can't join with thread 1: %s/n", strerror(err));    printf("thread 1 exit code %d/n", (int)tret);    err = pthread_join(tid2, &tret);    if(err != 0)        err_quit("can't join with thread 2: %s/n", strerror(err));    printf("thread 2 exit code %d/n", (int)tret);    exit(0);}

運行程序清單11-4中的程序會得到:

未命名

從輸出結果可以看出,兩個線程都正確地啟動和退出了,但是只調用了第二個線程的清理處理程序,所以如果線程是通過從它的啟動例程中返回而終止的話,那么它的清理處理程序就不會被調用,還要注意清理處理程序是按照與它們安裝時相反的順序被調用的。

現在可以開始看出線程函數和進程函數之間的相似之處。表11-1總結了這些相似的函數。

                                                  表11-1進程原語和線程原語的比較

2012080513265968

在默認情況下,線程的終止狀態會保存一直等到對該線程調用pthread_join。如果線程已經處于分離狀態(參考1http://linux.net527.cn/fuwuqiyingyong/Oracle/2012/0504/46837.html;參考2http://www.CUOXin.com/mydomain/archive/2011/08/14/2138454.htm),線程的底層存儲資源可以在線程終止時立即被收回

在任何一個時間點上,線程是可結合的(joinable),或者是分離的(detached)。一個可結合的線程能夠被其他線程收回其資源和殺死;在被其他線程回收之前,它的存儲器資源(如棧)是不釋放的。相反,一個分離的線程是不能被其他線程回收或殺死的,它的存儲器資源在它終止時由系統自動釋放。

線程的分離狀態決定一個線程以什么樣的方式來終止自己。線程的默認屬性,即為非分離狀態(即可結合的,joinable,需要回收),這種情況下,原有的線程等待創建的線程結束;只有當pthread_join()函數返回時,創建的線程才算終止,才能釋放自己占用的系統資源。而分離線程不是這樣子的,它沒有被其他的線程所等待,自己運行結束了,線程也就終止了,馬上釋放系統資源。程序員應該根據自己的需要,選擇適當的分離狀態。

當線程被分離時,并不能用pthread_join函數等待它的終止狀態。對分離狀態的線程進行pthread_join的調用會產生失敗,返回EINVAL。pthread_detach調用可以用于使線程進入分離狀態。

#include <pthread.h>int pthread_detach(pthread_t tid);返回值:若成功則返回0,否則返回錯誤編號

本篇博文內容摘自《UNIX環境高級編程》(第二版),僅作個人學習記錄所用。關于本書可參考:http://www.apuebook.com/


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久亚洲精品| 成人欧美一区二区三区黑人孕妇| 中文.日本.精品| 亚洲国产日韩欧美在线动漫| 亚洲国产精品高清久久久| 欧美极度另类性三渗透| 91精品视频专区| 久久精品色欧美aⅴ一区二区| 欧美日韩第一视频| 亚洲欧美精品中文字幕在线| 亚洲人成伊人成综合网久久久| 久久免费高清视频| 美女扒开尿口让男人操亚洲视频网站| 成人免费网视频| 国产精品白嫩初高中害羞小美女| 欧洲成人免费视频| 久久精品视频网站| 国产精品欧美日韩| 狠狠色狠狠色综合日日五| 久久影院资源站| 国产成人91久久精品| 日韩在线视频播放| 欧美激情区在线播放| 欧美重口另类videos人妖| 2019亚洲日韩新视频| 久久精品国产v日韩v亚洲| 国产精品爱啪在线线免费观看| 久久久影视精品| 热久久99这里有精品| 欧美成人免费播放| 亚洲人成电影网站色www| 日韩一二三在线视频播| 国产精品三级网站| 国产精品久久久久久一区二区| 日本高清视频精品| 亚洲国产精品久久久久| 日韩av在线精品| 国产一区二区三区精品久久久| 一区二区欧美日韩视频| 国产精品中文字幕在线| www.日本久久久久com.| 久久久av电影| 国产成人高潮免费观看精品| 国产日韩中文字幕| 日本免费在线精品| 欧美综合在线第二页| 亚洲综合色激情五月| 欧美激情综合色综合啪啪五月| 欧美插天视频在线播放| 亚洲国产成人久久综合一区| 日韩成人中文电影| 亚洲成人av在线播放| 91亚洲精品一区| 欧美最猛性xxxxx亚洲精品| 菠萝蜜影院一区二区免费| 高清视频欧美一级| 日韩成人黄色av| 国产美女久久久| 欧美在线视频一二三| 亚洲欧洲在线观看| 欧美国产日韩一区二区| 国产成人啪精品视频免费网| 亚洲色图综合久久| 亚洲bt天天射| 久久亚洲综合国产精品99麻豆精品福利| 国产成人精品一区二区在线| 欧美激情一级精品国产| 国产精品久久久久久超碰| 欧美一级大片在线观看| 久久久999国产精品| 国产精品对白刺激| 色与欲影视天天看综合网| 成人夜晚看av| 57pao成人国产永久免费| 国产精品视频中文字幕91| 欧美噜噜久久久xxx| 亚洲天堂网站在线观看视频| 久久久久这里只有精品| 国产精品视频色| 国产精品日韩电影| 欧美国产日产韩国视频| 日韩精品黄色网| 青青青国产精品一区二区| 欧美视频在线免费看| 米奇精品一区二区三区在线观看| 精品久久久久久久久久| 久久99久久99精品中文字幕| 欧美一级免费看| 国产精品美腿一区在线看| 高清亚洲成在人网站天堂| 热久久免费视频精品| 91精品国产高清| 国产精品白丝av嫩草影院| 精品视频久久久久久久| 亚洲无线码在线一区观看| 欧美午夜电影在线| 国产精品久久在线观看| 欧美激情在线观看视频| www国产91| 欧美性在线视频| 欧美成人精品xxx| 亚洲一区999| 国产午夜精品免费一区二区三区| 国产成人综合亚洲| 日韩在线免费高清视频| 日本成人精品在线| 91午夜理伦私人影院| 91老司机在线| 精品福利在线视频| 久久69精品久久久久久国产越南| 国产噜噜噜噜噜久久久久久久久| 亚洲美女在线视频| 久久国产精品99国产精| 久久精品国产96久久久香蕉| 国产精品欧美亚洲777777| www高清在线视频日韩欧美| 日韩最新av在线| 8090成年在线看片午夜| 欧美日韩在线观看视频小说| 国产精品亚洲自拍| 668精品在线视频| 日韩精品免费电影| 日产日韩在线亚洲欧美| 日韩欧美有码在线| 欧美精品九九久久| 欧美激情a在线| 国产精品网红福利| 亚洲成人黄色在线观看| 91中文字幕在线观看| 日韩欧美国产骚| 欧美高清在线视频观看不卡| 欧美日韩成人在线视频| 久久精品国产精品亚洲| 欧美诱惑福利视频| 亚洲电影免费观看高清完整版| 少妇av一区二区三区| 欧美亚洲激情在线| 亚洲免费av片| 欧美丰满老妇厨房牲生活| 久久好看免费视频| 国产欧美日韩视频| 97色在线观看| 国产精品国产亚洲伊人久久| 亚洲自拍偷拍区| 久久久亚洲福利精品午夜| 日韩在线免费观看视频| 国产在线视频一区| 日韩激情视频在线播放| 久久精品影视伊人网| 在线成人激情黄色| 欧美日韩性生活视频| 自拍亚洲一区欧美另类| 欧美成人一区二区三区电影| 欧美高清视频一区二区| 久久全国免费视频| 久久久久久久网站| 久久久av亚洲男天堂| 欧美性猛交丰臀xxxxx网站| 96pao国产成视频永久免费| www日韩欧美| 亚洲精品成人久久久| 欧美www视频在线观看| 狠狠色狠狠色综合日日五| 亚洲电影成人av99爱色|