Linux系統編程---14(回收子線程,回收多個子線程,線程分離,殺死線程)

回收子線程

pthread_join 函數

阻塞等待線程退出,獲取線程退出狀態 其作用,對應進程中 waitpid() 函數。

int	pthread_join	(pthread_t		thread,void**	retval); 

成功:0,失敗:錯誤號
參數:thread:線程ID(注意 :不是指針);retval:存儲線程結束狀態
對比記憶:

  1. 進程中:main 返回值、exit 參數–>int;等待子進程結束 wait 函數參數–>int*
  2. 線程中:線程主函數返回值、pthread_exit-->void*;等待線程結束 pthread_join 函數參數–>void**
  3. 對于進程而言,wait函數的返回值是int,所以獲取退出值使用int*
  4. 對于線程,void*作為函數返回值,回收使用void**
示例1
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>typedef struct{int a;int b;
}exit_t;void * tfn(void *arg)   //子線程函數
{//子線程函數中定義 ret;exit_t *ret; //用結構體定義一個變量ret=malloc(sizeof(exit_t));ret->a = 100;ret->b = 300;//返回ret 這個值,線程退出pthread_exit((void *)ret);
}int main(void)
{pthread_t tid;exit_t *retval;pthread_create(&tid,NULL,tfn,NULL);/*調用pthread_join可以獲取線程退出狀態*///第一個回收線程ID,第二個回收退出的值                                   pthread_join(tid,(void **)&retval);   //wait(&status);printf("a = %d,b = %d\n",retval->a,retval->b);return 0;
}

在這里插入圖片描述

注意事項

調用該函數的線程將掛起等待,直到 id 為 thread 的線程終止。 thread 線程以不同的方法終止,通過 pthread_join 得到的終止狀態是不同的,總結如下:

  1. 如果 thread 線程通過 return 返回,retval 所指向的單元里存放的是 thread 線程函數的返回值。
  2. 如果 thread 線程被別的線程調用 pthread_cancel 異常終止掉,retval 所指向的單元里存放的是常數PTHREAD_CANCELED。
  3. 如果 thread 線程是自己調用 pthread_exit 終止的,retval 所指向的單元存放的是傳給 pthread_exit 的參數。
  4. 如果對 thread 線程的終止狀態不感興趣,可以傳 NULL 給 retval 參數。

示例2

#include<stdio.h>                                                            
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<string.h>typedef struct {char ch;int var;char str[64];
}exit_t;void *thrd_func(void *arg)
{//創建結構體變量exit_t * retvar = (exit_t *)malloc(sizeof(exit_t));//賦值retvar->ch='m';retvar->var = 200;strcpy(retvar->str,"我的返回值");//子線程退出pthread_exit((void *)retvar);}int main(void)
{pthread_t tid;int ret;exit_t * retval;//主控線程IDprintf(" In main1 id = %lu,pid = %u\n",pthread_self(),getpid());ret = pthread_create(&tid,NULL,thrd_func,NULL);if(ret != 0){fprintf(stderr,"pthread_create error:%s\n",strerror(ret));exit(1);}pthread_join(tid,(void **)&retval);printf("子線程返回值為\n");printf("ch = %c ,var = %d,str = %s\n",retval->ch,retval->var,retval->str);pthread_exit((void *)1);return 0;
}                                              

在這里插入圖片描述

使用 pthread_join 函數將循環創建的多個子線程回收。
/*回收多個子線程*/                                                           
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>int var=100;void *tfn(void *arg)  //每個子線程進行回收
{int i;i = (int)arg;sleep(i);  //輸出有順序if(i == 1){var = 333;printf("var = %d\n",var);return (void *)var;}else if(i == 3){var = 777;printf("I'm %d th 線程,線程ID為 %lu var = %d\n",i+1,pthread_self(),var);pthread_exit((void *)var);}else {printf("I'm %d th 線程,線程ID = %lu\n var = %d\n",i+1,pthread_self(),var);pthread_exit((void *)var);}return NULL;
}int main(void)
{pthread_t tid[5];int i;int *ret[5]; //保存 5個線程的退出值for(i = 0;i < 5; i++)//循環創建多個子線程pthread_create(&tid[i],NULL,tfn,(void*)i);for(i=0;i < 5; i++){ //對多個子線程進行回收pthread_join(tid[i],(void **)&ret[i]);printf("-----------%d th ret = %d\n",i,(int)ret[i]);}printf("I'm main 線程 tid = %lu\t var = %d\n",pthread_self(),var);//主控線程也打印777,原因是共享全局變量sleep(i);return 0;
}                 

在這里插入圖片描述

線程分離

pthread_detach 函數

進程當中沒有
實現線程分離
int pthread_detach(pthread_t thread); 成功:0;失敗:錯誤號

  1. 線程分離狀態:指定該狀態,線程主動與主控線程斷開關系。線程結束后,其退出狀態不由其他線程獲取,而 直接自己自動釋放。網絡、多線程服務器常用。
  2. 進程若有該機制,將不會產生僵尸進程。僵尸進程的產生主要由于進程死后,大部分資源被釋放,一點殘留資 源仍存于系統中,導致內核認為該進程仍存在。
    也可使用 pthread_create 函數參 2(線程屬性)來設置線程分離。
使用 pthread_detach 函數實現線程分離
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>void *tfn(void *arg)
{int n=3;while(n--){printf("thread count %d\n",n);sleep(1);}   return (void *)1;
}int main(void)
{pthread_t tid;void *tret;int err;pthread_create(&tid,NULL,tfn,NULL);pthread_detach(tid);        //讓線程分離   ----自動退出,無系統殘留資源while(1){err = pthread_join(tid,&tret);printf("---------err= %d\n",err);if(err != 0)fprintf(stderr,"thread error: %s\n",strerror(err));              elsefprintf(stderr,"thread exit code %d\n",(int)tret);sleep(1);}       return 0;
}

在這里插入圖片描述

注意事項

一般情況下,線程終止后,其終止狀態一直保留到其它線程調用 pthread_join 獲取它的狀態為止。但是線程也 可以被置為 detach 狀態,這樣的線程一旦終止就立刻回收它占用的所有資源,而不保留終止狀態。**不能對一個已 經處于 detach 狀態的線程調用 pthread_join,這樣的調用將返回 EINVAL 錯誤。**也就是說,如果已經對一個線程調用 了 pthread_detach 就不能再調用 pthread_join 了。

殺死線程

pthread_cancel 函數

殺死(取消)線程 其作用,對應進程中 kill() 函數。
int pthread_cancel(pthread_t thread); 成功:0;失敗:錯誤號
注意線程的取消并不是實時的,而有一定的延時。需要等待線程到達某個取消點(檢查點)。

  1. 類似于玩游戲存檔,必須到達指定的場所(存檔點,如:客棧、倉庫、城里等)才能存儲進度。殺死線程也不是 立刻就能完成,必須要到達取消點。
  2. 取消點:是線程檢查是否被取消,并按請求進行動作的一個位置。通常是一些系統調用 creat,open,pause, close,read,write..... 執行命令 man 7 pthreads 可以查看具備這些取消點的系統調用列表。也可參閱 APUE.12.7 取消選項小節。
    可粗略認為一個系統調用(進入內核)即為一個取消點。如線程中沒有取消點,可以通過調用 pthreestcancel 函數 自行設置一個取消點。
  3. 被取消的線程, 退出值定義在Linux的pthread庫中。常數PTHREAD_CANCELED的值是**-1**。可在頭文件pthread.h 中找到它的定義:#define PTHREAD_CANCELED((void*)-1)。因此當我們對一個已經被取消的線程使用 pthread_join 回收時,得到的返回值為-1。
終止線程的三種方法
/*三種退出線程的方法*/                                                       #include<stdio.h>
#include<string.h>
#include<pthread.h>void *tfn1(void *arg)  //第一個線程
{printf("thread 1 returning\n");return (void *)111;
}void *tfn2(void *arg)   //第二個線程
{printf("thread 2 exiting\n");pthread_exit((void *)222);
}void *tfn3(void *arg)   //第三個線程
{while(1){printf("thread 3:I'm going to die in 3 seconds ....\n");sleep(1);//pthread_testcancel();//自己添加取消點}return (void *)666;
}int main(void)
{pthread_t tid;void *tret = NULL;pthread_create(&tid,NULL,tfn1,NULL);pthread_join(tid,&tret);printf("thread 1 exit code = %d\n\n",(int)tret);pthread_create(&tid,NULL,tfn2,NULL);pthread_join(tid,&tret);printf("thread 2 exit code = %d\n\n",(int)tret);pthread_create(&tid,NULL,tfn3,NULL);sleep(3);pthread_cancel(tid);pthread_join(tid,&tret);printf("thread 3 exit code = %d\n\n",(int)tret);return 0;
}        

在這里插入圖片描述
當把一個線程殺死后,它的返回值是-1;

終止線程方式

總結:終止某個線程而不終止整個進程,
有三種方法:

  1. 從線程主函數 return。這種方法對主控線程不適用,從 main 函數 return 相當于調用 exit。
  2. 一個線程可以調用 pthread_cancel 終止同一進程中的另一個線程。
  3. 線程可以調用 pthread_exit 終止自己。

pthread_equal 函數

比較兩個線程 ID 是否相等。
int pthread_equal (pthread_t t1,pthread_t t2); 有可能 Linux 在未來線程 ID pthread_t 類型被修改為結構體實現。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383223.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383223.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383223.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux系統編程----15(線程與進程函數之間的對比,線程屬性及其函數,線程屬性控制流程,線程使用注意事項,線程庫)

對比 進程 線程 fork pthread_create exit (10) pthread_exit &#xff08;void *&#xff09; wait (int *) pthread_join &#xff08;&#xff0c;void **&#xff09;阻塞 kill pthread_cancel ();必須到取消點&#xff08;檢查點&#xff09;&#xff1a;…

內核雙向循環鏈表

#include <string.h>#include <stdio.h>#include <stdlib.h>#include<malloc.h>#include <arpa/inet.h>//鏈表頭結構struct list_head{struct list_head *next,*prev;};//真正實現鏈表插入操作void _list_add(struct list_head *nnew,struct lis…

Linux系統編程----16(線程同步,互斥量 mutex,互斥鎖的相關函數,死鎖,讀寫鎖)

同步概念 所謂同步&#xff0c;即同時起步&#xff0c;協調一致。不同的對象&#xff0c;對“同步”的理解方式略有不同。如&#xff0c;設備同步&#xff0c;是指在兩 個設備之間規定一個共同的時間參考&#xff1b;數據庫同步&#xff0c;是指讓兩個或多個數據庫內容保持一致…

轉移字符的轉換

使得網頁上不會顯示 \x0a\x0a \x0a \x0a \x0a \x0a 類似的字符static int te_escape_isDec(char *ptr, unsigned int len) { …

Linux系統編程---17(條件變量及其函數,生產者消費者條件變量模型,生產者與消費者模型(線程安全隊列),條件變量優點,信號量及其主要函數,信號量與條件變量的區別,)

條件變量 條件變量本身不是鎖&#xff01;但它也可以造成線程阻塞。通常與互斥鎖配合使用。給多線程提供一個會合的場所。 主要應用函數&#xff1a; pthread_cond_init 函數pthread_cond_destroy 函數pthread_cond_wait 函數pthread_cond_timedwait 函數pthread_cond_signa…

好友

http://blog.csdn.net/liangyuannao/article/details/8583139

Linux系統編程---18(線程池相關概念及其實現)

線程池 概念&#xff1a; 一堆線程任務隊列 作用 避免大量線程頻繁的創建/銷毀時間成本避免瞬間大量線程創建耗盡資源&#xff0c;程序崩潰危險 實現 創建固定數量的線程創建一個線程安全的任務隊列 一種線程使用模式。 線程過多會帶來調度開銷&#xff0c;進而影響緩…

設計模式--1(設計模式基礎,設計模式基本原則,設計模式分類)

設計模式基礎 模式 在一定環境中解決某一問題的方案&#xff0c;包括三個基本元素–問題&#xff0c;解決方案和環境。大白話&#xff1a;在一定環境下&#xff0c;用固定套路解決問題。 設計模式 是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使…

source insight 使用技巧

source insight 使用技巧 1 sourceinsight screen font 的默認字體是Verdana的&#xff0c;它是一直變寬字體。在Document style中可以將字體改為定寬的Courier2 document options->auto indent 去掉indent Open Brace和Indent Close Brace的效果: 繼上一段&#xff0c;在…

設計模式----2(簡單工廠模式的概念,簡單工廠模式的實現,簡單工廠模式的優缺點)

簡單工廠模式 簡單工廠模式的概念 簡單工廠模式屬于類的創建型模式,又叫做靜態工廠方法模式。通過專門定義一個類來負 責創建其他類的實例&#xff0c;被創建的實例通常都具有共同的父類。 具體分類 工廠&#xff08;Creator&#xff09;角色 簡單工廠模式的核心&#xff0…

Redis常見問題及其一些重點知識總結

1、什么是 Redis&#xff1f;簡述它的優缺點&#xff1f; Redis 的全稱是&#xff1a;Remote Dictionary.Server&#xff0c;本質上是一個 Key-Value 類型的內存數據庫&#xff0c;很像 memcached&#xff0c;整個數據庫統統加載在內存當中進行操作&#xff0c;定期通過異步操…

shell生成隨機文件名

1 #!/bin/bash 2 # tempfile-name.sh: 臨時文件名產生器 3 4 BASE_STRmcookie # 32-字符的 magic cookie. 5 POS11 # 字符串中隨便的一個位置. 6 LEN5 # 取得 $LEN 長度連續的字符串. 7 8 prefixtemp # 最終的一個臨時文…

設計模式---3(工廠方法模式的概念,工廠方法模式的實現,工廠方法模式和簡單工廠模式比較)

工廠方法模式 概念 工廠方法模式同樣屬于類的創建型模式又被稱為多態工廠模式 。 工廠方法模式的意義 定義一個創建產品對象的工廠接口&#xff0c;將實際創建工作推遲到子類當中。 核心工廠類不再負責產品的創建&#xff0c;這樣核心類成為一個抽象工廠角色&#xff0c;僅…

設計模式---4(抽象工廠模式的概念,產品組和產品等級的概念,抽象工廠模式的實現)

抽象工廠模式 抽象工廠模式的概念 抽象工廠模式是所有形態的工廠模式中最為抽象和最其一般性的。抽象工廠模式可以向 客戶端提供一個接口&#xff0c;使得客戶端在不必指定產品的具體類型的情況下&#xff0c;能夠創建多個產品 族的產品對象。 抽象工廠的角色及其職責 抽象工…

Win32項目關于MessageBox參數的詳細說明

函數功能&#xff1a;該函數創建、顯示、和操作一個消息框。消息框含有應用程序定義的消息和標題&#xff0c;加上預定義圖標與Push&#xff08;下按&#xff09;按鈕的任何組合。 函數原型&#xff1a;int MessageBox(HWND hWnd,LPCTSTR IpCaption,UINT…

w3af解析

1. w3af簡介 w3afis a Web Application Attack and Audit Framework.即Web應用攻擊和審計框架。w3af用python編寫&#xff0c;依賴的庫主要有2類&#xff0c;分別如下&#xff1a; <1> Core requirements: Python 2.6 fpconst-0.7.2&#xff1a;用于處理IEEE 754浮點…

1.c++中初始化列表和構造函數初始化的區別是什么?2.類的成員變量的初始化順序是按照聲明順序嗎?

初始化列表和構造函數初始化的區別是什么&#xff1f; 初始化和賦值對內置類型的成員沒有太大的區別&#xff0c;在成員初始化列表和構造函數體內進行&#xff0c;在性能和結果上都是一樣的。只有一些需要注意的事項 初始化列表一般情況如下&#xff1a; Date(int year, int …

設計模式---5(建造者模式的概念及其實現,建造者模式的角色與職責,建造者模式和工廠模式的區別)

建造者模式 建造者模式的概念 Builder 模式也叫建造者模式或者生成器模式&#xff0c;是由 GoF 提出的 23 種設計模式中的一種。 Builder 模式是一種對象創建型模式之一&#xff0c;用來隱藏復合對象的創建過程&#xff0c;它把復合對象的 創建過程加以抽象&#xff0c;通過子…

system阻塞SIGCHLD信號原因

system阻塞SIGCHLD信號原因 標簽&#xff1a; c 2014-11-08 11:58 198人閱讀 評論(0) 收藏 舉報 分類&#xff1a; linux編程&#xff08;1&#xff09; 代碼1&#xff1a;APUE10.18節的system函數源代碼 int system(const char *cmdstring) /* with appropriate signal ha…

設計模式6---(單例模式的概念及其實現(懶漢式和餓漢式),線程安全)

單例模式 單例模式的概念 單例模式是一種對象創建型模式&#xff0c;使用單例模式&#xff0c;可以保證為一個類只生成唯一的實例對象。也就是說&#xff0c;在整個程序空間中&#xff0c;該類只存在一個實例對象。 GoF 對單例模式的定義是&#xff1a;保證一個類、只有一個實…