最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言如何正確的終止正在運行的子線程

 更新時間:2019年02月17日 09:24:41   作者:大熊(先生)  
這篇文章主要介紹了C語言如何正確的終止正在運行的子線程,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

最近開發(fā)一些東西,線程數(shù)非常之多,當用戶輸入Ctrl+C的情形下,默認的信號處理會把程序退出,這時有可能會有很多線程的資源沒有得到很好的釋放,造成了內(nèi)存泄露等等諸如此類的問題,本文就是圍繞著這么一個使用場景討論如何正確的終止正在運行的子線程。其實本文更確切的說是解決如何從待終止線程外部安全的終止正在運行的線程

首先我們來看一下,讓當前正在運行的子線程停止的所有方法

1.任何一個線程調(diào)用exit

2.pthread_exit

3.pthread_kill

4.pthread_cancel

下面我們一一分析各種終止正在運行的程序的方法 

任何一個線程調(diào)用exit

任何一個線程只要調(diào)用了exit都會導致進程結束,各種子線程當然也能很好的結束了,可是這種退出會有一個資源釋放的問題.我們知道當一個進程終止時,內(nèi)核對該進程所有尚未關閉的文件描述符調(diào)用close關閉,所以即使用戶程序不調(diào)用close,在終止時內(nèi)核也會自動關閉它打開的所有文件。沒錯,標準C++ IO流也會很好的在exit退出時得到flush并且釋放資源,這些東西并不會造成資源的浪費(系統(tǒng)調(diào)用main函數(shù)入口類似于exit(main(argc,argv))).表面上似乎所有的問題都能隨著進程的結束來得到很好的處理,其實并不然,我們程序從堆上分配的內(nèi)存就不能得到很好的釋放,如new ,delete后的存儲空間,這些空間進程結束并不會幫你把這部分內(nèi)存歸還給內(nèi)存.(本文初稿時,因基礎不牢固,此處寫錯,事實上無論進程這樣結束,系統(tǒng)都將會釋放掉所有代碼所申請的資源,無論是堆上的還是棧上的。(感謝ZKey的指導)。這種結束所有線程(包括主線程)的方式實際上在很多時候是非??扇〉?,但是對于針對關閉時進行一些別的邏輯的處理(指非資源釋放邏輯)就不會很好,例如我想在程序被kill掉之前統(tǒng)計一下完成了多少的工作,這個統(tǒng)計類似于MapReduce,需要去每個線程獲取,并且最后歸并程一個統(tǒng)一的結果等等場景)

pthread_exit

此函數(shù)的使用場景是當前運行的線程運行pthread_exit得到退出,對于各個子線程能夠清楚地知道自己在什么時候結束的情景下,非常好用,可是實際上往往很多時候一個線程不能知道知道在什么時候該結束,例如遭遇Ctrl+C時,kill進程時,當然如果排除所有的外界干擾的話,那就讓每個線程干完自己的事情后,然后自覺地乖乖的調(diào)用pthread_exit就可以了,這并不是本文需要討論的內(nèi)容,本文的情景就是討論如何處理特殊情況。

這里還有一種方法,既然子線程可以通過pthread_exit來正確退出,那么我們可以在遭遇Ctrl+C時,kill進程時處理signal信號,然后分別給在某一個線程可以訪問的公共區(qū)域存上一個flag變量,線程內(nèi)部每運行一段時間(很短)來檢查一下flag,若發(fā)現(xiàn)需要終止自己時,自己調(diào)用pthread_exit,此法有一個弱點就是當子線程需要進行阻塞的操作時,可能無暇顧及檢查flag,例如socket阻塞操作。如果你的子線程的任務基本沒有非阻塞的函數(shù),那么這么干也不失為一種很好的方案。

pthread_kill

不要被這個可怕的邪惡的名字所嚇倒,其實pthread_kill并不像他的名字那樣威力大,使用之后,你會感覺,他徒有虛名而已

pthread_kill的職責其實只是向指定的線程發(fā)送signal信號而已,并沒有真正的kill掉一個線程,當然這里需要說明一下,有些信號的默認行為就是exit,那此時你使用pthread_kill發(fā)送信號給目標線程,目標線程會根據(jù)這個信號的默認行為進行操作,有可能是exit。當然我們同時也可以更改獲取某個信號的行為,以此來達到我們終止子線程的目的。

#define _MULTI_THREADED
#include <pthread.h>
#include <stdio.h>
#include <signal.h>
#include "check.h"

#define NUMTHREADS 3
void sighand(int signo);

void *threadfunc(void *parm)
{
 pthread_t       self = pthread_self();
 pthread_id_np_t    tid;
 int          rc;

 pthread_getunique_np(&self, &tid);
 printf("Thread 0x%.8x %.8x entered\n", tid);
 errno = 0;
 rc = sleep(30);
 if (rc != 0 && errno == EINTR) {
  printf("Thread 0x%.8x %.8x got a signal delivered to it\n",
      tid);
  return NULL;
 }
 printf("Thread 0x%.8x %.8x did not get expected results! rc=%d, errno=%d\n",
     tid, rc, errno);
 return NULL;
}

int main(int argc, char **argv)
{
 int           rc;
 int           i;
 struct sigaction    actions;
 pthread_t        threads[NUMTHREADS];

 printf("Enter Testcase - %s\n", argv[0]);
 
 printf("Set up the alarm handler for the process\n");
 memset(&actions, 0, sizeof(actions));
 sigemptyset(&actions.sa_mask);
 actions.sa_flags = 0;
 actions.sa_handler = sighand;

 rc = sigaction(SIGALRM,&actions,NULL);
 checkResults("sigaction\n", rc);

 for(i=0; i<NUMTHREADS; ++i) {
  rc = pthread_create(&threads[i], NULL, threadfunc, NULL);
  checkResults("pthread_create()\n", rc);
 }

 sleep(3);
 for(i=0; i<NUMTHREADS; ++i) {
  rc = pthread_kill(threads[i], SIGALRM);
  checkResults("pthread_kill()\n", rc);
 }

 for(i=0; i<NUMTHREADS; ++i) {
  rc = pthread_join(threads[i], NULL);
  checkResults("pthread_join()\n", rc);
 }
 printf("Main completed\n");
 return 0;
}

void sighand(int signo)
{
 pthread_t       self = pthread_self();
 pthread_id_np_t    tid;
 
 pthread_getunique_np(&self, &tid);
 printf("Thread 0x%.8x %.8x in signal handler\n",
     tid);
 return;
}

運行輸出為:

Output:

Enter Testcase - QP0WTEST/TPKILL0
Set up the alarm handler for the process
Thread 0x00000000 0000000c entered
Thread 0x00000000 0000000d entered
Thread 0x00000000 0000000e entered
Thread 0x00000000 0000000c in signal handler
Thread 0x00000000 0000000c got a signal delivered to it
Thread 0x00000000 0000000d in signal handler
Thread 0x00000000 0000000d got a signal delivered to it
Thread 0x00000000 0000000e in signal handler
Thread 0x00000000 0000000e got a signal delivered to it
Main completed

我們可以通過截獲的signal信號,來釋放掉線程申請的資源,可是遺憾的是我們不能再signal處理里調(diào)用pthread_exit來終結掉線程,因為pthread_exit是中介當前線程,而signal被調(diào)用的方式可以理解為內(nèi)核的回調(diào),不是在同一個線程運行的,所以這里只能做處理釋放資源的事情,線程內(nèi)部只有判斷有沒有被中斷(一般是EINTR)來斷定是否要求自己結束,判定后可以調(diào)用pthread_exit退出。

此法對于一般的操作也是非??尚械模墒窃谟械那闆r下就不是一個比較好的方法了,比如我們有一些線程在處理網(wǎng)絡IO事件,假設它是一種一個客戶端對應一個服務器線程,阻塞從Socket中讀消息的情況。我們一般在網(wǎng)絡IO的庫里面回家上對EINTR信號的處理,例如recv時發(fā)現(xiàn)返回值小于0,檢查error后,會進行他對應的操作。有可能他會再recv一次,那就相當于我的線程根本就不回終止,因為網(wǎng)絡IO的類有可能不知道在獲取EINTR時要終止線程。也就是說這不是一個特別好的可移植方案,如果你線程里的操作使用了很多外來的不太熟悉的類,而且你并不是他對EINTR的處理手段是什么,這是你在使用這樣的方法來終止就有可能出問題了。而且如果你不是特別熟悉這方面的話你會很苦惱,“為什么我的測試代碼全是ok的,一加入你們部門開發(fā)的框架進來就不ok了,肯定是你們框架出問題了”。好了,為了不必要的麻煩,我最后沒有使用這個方案。

pthread_cancel

這個方案是我最終采用的方案,我認為是解決這個問題,通用的最好的解決方案,雖然前面其他方案的有些問題他可能也不好解決,但是相比較而言,還是相當不錯的

pthread_cancel可以單獨使用,因為在很多系統(tǒng)函數(shù)里面本身就有很多的斷點,當調(diào)用這些系統(tǒng)函數(shù)時就會命中其內(nèi)部的斷點來結束線程,如下面的代碼中,即便注釋掉我們自己設置的斷點pthread_testcancel()程序還是一樣的會被成功的cancel掉,因為printf函數(shù)內(nèi)部有取消點(如果大家想了解更多的函數(shù)的取消點情況,可以閱讀《Unix高級環(huán)境編程》的線程部分)

#include <pthread.h>
#include <stdio.h>
#include<stdlib.h>
#include <unistd.h>
void *threadfunc(void *parm)
{
 printf("Entered secondary thread\n");
 while (1) {
  printf("Secondary thread is looping\n");
  pthread_testcancel();
  sleep(1);
 }
 return NULL;
}

int main(int argc, char **argv)
{
 pthread_t       thread;
 int          rc=0;

 printf("Entering testcase\n");

 /* Create a thread using default attributes */
 printf("Create thread using the NULL attributes\n");
 rc = pthread_create(&thread, NULL, threadfunc, NULL);
 checkResults("pthread_create(NULL)\n", rc);

 /* sleep() is not a very robust way to wait for the thread */
 sleep(1);

 printf("Cancel the thread\n");
 rc = pthread_cancel(thread);
 checkResults("pthread_cancel()\n", rc);

 /* sleep() is not a very robust way to wait for the thread */
 sleep(10);
 printf("Main completed\n");
 return 0;
}

輸出:

Entering testcase
Create thread using the NULL attributes
Entered secondary thread
Secondary thread is looping
Cancel the thread
Main completed

POSIX保證了絕大部分的系統(tǒng)調(diào)用函數(shù)內(nèi)部有取消點,我們看到很多在cancel調(diào)用的情景下,recv和send函數(shù)最后都會設置pthread_testcancel()取消點,其實這不是那么有必要的,那么究竟什么時候該pthread_testcancel()出場呢?《Unix高級環(huán)境編程》也說了,當遇到大量的基礎計算時(如科學計算),需要自己來設置取消點。

ok,得益于pthread_cancel,我們很輕松的把線程可以cancel掉,可是我們的資源呢?何時釋放...

下面來看兩個pthread函數(shù)

1.void pthread_cleanup_push(void (*routine)(void *), void *arg); 
2.void pthread_cleanup_pop(int execute);

這兩個函數(shù)能夠保證在 1函數(shù)調(diào)用之后,2函數(shù)調(diào)用之前的任何形式的線程結束調(diào)用向pthread_cleanup_push注冊的回調(diào)函數(shù)
另外我們還可通過下面這個函數(shù)來設置一些狀態(tài)

int pthread_setcanceltype(int type, int *oldtype);

Cancelability Cancelability State Cancelability Type
disabled PTHREAD_CANCEL_DISABLE PTHREAD_CANCEL_DEFERRED
disabled PTHREAD_CANCEL_DISABLE PTHREAD_CANCEL_ASYNCHRONOUS
deferred PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_DEFERRED
asynchronous PTHREAD_CANCEL_ENABLE PTHREAD_CANCEL_ASYNCHRONOUS

當我們設置type為PTHREAD_CANCEL_ASYNCHRONOUS時,線程并不會等待命中取消點才結束,而是立馬結束

好了,下面貼代碼:

#include <pthread.h>                              
#include <stdio.h>                               
#include <stdlib.h>                               
#include <unistd.h>                               
#include <errno.h>                                        
int footprint=0;
char *storage; 
void freerc(void *s)
{
  free(s);
  puts("the free called");  
}                                

static void checkResults(char *string, int rc) {
 if (rc) {
  printf("Error on : %s, rc=%d",
      string, rc);
  exit(EXIT_FAILURE);
 }
 return;
}
                                        
void *thread(void *arg) {                                                          
 int      rc=0, oldState=0; 
 rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState);  //close the cancel switch  
 checkResults("pthread_setcancelstate()\n", rc);                                    
 if ((storage = (char*) malloc(80)) == NULL) {                 
  perror("malloc() failed");                         
  exit(6);                                  
 }                                       
  rc = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,&oldState);  //open the cancel switch                                    
  checkResults("pthread_setcancelstate(2)\n", rc); 
/* Plan to release storage even if thread doesn't exit normally */      
                                        
 pthread_cleanup_push(freerc, storage);  /*the free is method here  you can use your own method here*/                    
                                        
 puts("thread has obtained storage and is waiting to be cancelled");      
 footprint++;                                 
 while (1)
  {   
     pthread_testcancel();  //make a break point here   
      //pthread_exit(NULL);  //test exit to exam whether the freerc method called                           
      sleep(1); 
  }                                 
                                        
 pthread_cleanup_pop(1);                            
}                                        
                                        
main() {                                    
 pthread_t thid; 
 void         *status=NULL;                               
                                        
 if (pthread_create(&thid, NULL, thread, NULL) != 0) {             
  perror("pthread_create() error");                      
  exit(1);                                  
 }                                       
                                        
 while (footprint == 0)                            
  sleep(1);                                  
                                        
 puts("IPT is cancelling thread");                       
                                        
 if (pthread_cancel(thid) != 0) {                       
  perror("pthread_cancel() error");  
  sleep(2);                    
  exit(3);                                  
 }                                       
                                        
 if (pthread_join(thid, &status) != 0) { 
  if(status != PTHREAD_CANCELED){                   
    perror("pthread_join() error");                       
    exit(4);
  }                                  
 }
 if(status == PTHREAD_CANCELED)
  puts("PTHREAD_CANCELED");
   
 puts("main exit");                                    
}

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 深度解析三個常見的C語言內(nèi)存函數(shù)

    深度解析三個常見的C語言內(nèi)存函數(shù)

    這篇文章主要深度解析了三個常見的C語言內(nèi)存函數(shù)memcpy,memmove,memcmp,所以本文將對memcpy,memmove,memcmp 三個函數(shù)進行詳解和模擬實現(xiàn),需要的朋友可以參考下
    2023-07-07
  • C語言二叉樹的三種遍歷方式的實現(xiàn)及原理

    C語言二叉樹的三種遍歷方式的實現(xiàn)及原理

    這篇文章主要介紹了C語言二叉樹的三種遍歷方式的實現(xiàn)及原理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-07-07
  • Vscode搭建遠程c開發(fā)環(huán)境的圖文教程

    Vscode搭建遠程c開發(fā)環(huán)境的圖文教程

    很久沒有寫C語言了,今天抽空學習下C語言知識,接下來通過本文給大家介紹Vscode搭建遠程c開發(fā)環(huán)境的詳細步驟,本文通過圖文實例代碼相結合給大家介紹的非常詳細,需要的朋友參考下吧
    2021-11-11
  • C語言實現(xiàn)個人財務管理

    C語言實現(xiàn)個人財務管理

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)個人財務管理,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • C++設計與實現(xiàn)ORM系統(tǒng)實例詳解

    C++設計與實現(xiàn)ORM系統(tǒng)實例詳解

    這篇文章主要為大家介紹了C++設計與實現(xiàn)ORM系統(tǒng)實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • C++ map用法總結(整理)

    C++ map用法總結(整理)

    這篇文章主要介紹了C++ map用法總結(整理),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • Qt實現(xiàn)柵格布局效果

    Qt實現(xiàn)柵格布局效果

    這篇文章主要為大家詳細介紹了Qt實現(xiàn)柵格布局效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • c++實現(xiàn)加載so動態(tài)庫中的資源

    c++實現(xiàn)加載so動態(tài)庫中的資源

    下面小編就為大家?guī)硪黄猚++實現(xiàn)加載so動態(tài)庫中的資源。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • 利用C++的基本算法實現(xiàn)十個數(shù)排序

    利用C++的基本算法實現(xiàn)十個數(shù)排序

    以下是對利用C++的基本算法實現(xiàn)十個數(shù)排序的代碼進行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-10-10
  • C語言示例講解動態(tài)/文件/靜態(tài)功能版本的通訊錄實現(xiàn)

    C語言示例講解動態(tài)/文件/靜態(tài)功能版本的通訊錄實現(xiàn)

    通訊錄是一個可以記錄親人、好友信息的工具,這篇文章主要為大家詳細介紹了C語言實現(xiàn)通訊錄管理,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07

最新評論

崇阳县| 云安县| 闽清县| 合作市| 宝山区| 巨野县| 遂昌县| 嘉义市| 新乡县| 四子王旗| 昌黎县| 清远市| 青阳县| 兰考县| 共和县| 开封市| 淮北市| 三河市| 科技| 舟曲县| 磐安县| 友谊县| 双城市| 长宁县| 灯塔市| 武穴市| 武平县| 新巴尔虎左旗| 沐川县| 昆明市| 高雄县| 上犹县| 保德县| 阿坝| 平南县| 辰溪县| 怀来县| 洛浦县| 岳西县| 县级市| 双牌县|