Linux中多線程操作函數pthread_exit()、pthread_jion()、pthread_detach()、pthread_cancel()



簡 述: 上一篇講解了多線程的入門的知識,如何創建多線程程序,以及從虛擬地址空間和 PCB 分析線程的一些細節。本章再講述一些線程操作相關的函數:

  • pthread_exit(): 退出一個線程,不會影響其他線程的
  • pthread_jion(): 阻塞等待線程退出,獲取線程退出的狀態
  • pthread_detach(): 設置線程分離的屬性
  • pthread_cancel(): 殺死(取消)一個線程
  • pthread_equal(): 判斷兩個線程是否相等,預留函數

編程環境:

💻: uos20 📎 gcc/g++ 8.3 📎 gdb8.0

💻: MacOS 10.14 📎 gcc/g++ 9.2 📎 gdb8.3


單個線程退出 pthread_exit():

  • 作用: 一個進程的退出使用 exit(0); 而退出一個線程,使用 pthread_exit(NULL)
void pthread_exit(void *value_ptr);
  • 參數:

    • value_ptr:必須指向全局,或者堆。是一個傳出參數,用來在該線程結束推出的時候,傳輸一個內容。若是指向局部變量,該線程被銷燬了的話,其他線程可能訪問不到此塊數據塊。
  • 寫一個例子:

    #include <stdio.h>
    #include <unistd.h>
    #include <pthread.h>
    
    int num = 13; //設置爲全局變量,在全局區域,共享
    
    void* myfun(void* arg);
    
    int main(int argc, char *argv[])
    {
        void* p = (void *)&num;  //傳一個地址進去(voi* 也是 4 個字節)
        pthread_t id[5] = {0};
        for (int i = 0; i < 5; i++) {
            pthread_create(&(id[i]), NULL, myfun, p);
            printf("i = %d, thread id: %ld\n", i, id[i]);
        }
    
        // pthread_exit(nullptr);  //終止主線程
        int j = 0;
        while (true) {
            sleep(1);
            printf ("main thread-----%d------\n", j++);
        }
        
        return 0;
    }
    
    void* myfun(void* arg)
    {
        for (int i = 0; i < 5; i++) {
            printf ("child thread-----%d------\n", i);
    
            if (i == 2) {
                 _exit(0); //退出進程
                // pthread_exit(nullptr);  //終止主線程
            }        
        }
    
        return nullptr;
    }
    
  • 運行結果:


阻塞等待退出線程退出 pthread_jion():

  • 作用:

    阻塞等待線程退出,獲取線程退出的狀態

int pthread_join(pthread_t thread, void **value_ptr);
  • 參數:

    • thread: 要回收的子線程的 id
    • value_ptr:讀取線程退出時候的攜帶信息狀態;指向的內存和 pthread_exit 的參數是指向同一塊內存地址 。在上一個函數 pthread_exit(void *value_ptr) 中,線程退出的時候,傳出來了全局變量的指針; 而這裏第二個參數,此二級指針就可以讀出來這個值。
  • 寫了一例子:

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    
    int number = 1234; //要是一個全局的變量哦,或者是堆的空間
    void* myfun(void* arg);
    
    int main(int argc, char *argv[])
    {
        pthread_t pthread = 0;
        int ret = pthread_create(&pthread, NULL, myfun, NULL);
    
        if (ret != 0)
            printf("error: %s\n", strerror(ret));
    
        printf("parent thread id: %ld\n", pthread_self);
    
        void* ptr = nullptr;
    
        pthread_join(pthread, &ptr); //阻塞等待子線程退出,並且回收 pcb
        printf("number = %d\n", *((int*)ptr));
    
        int i = 0;
        while (i < 10 ) {
            printf("parent i = %d\n", i++);
        }
        
        return 0;
    }
    
    void* myfun(void* arg)
    {
        printf("child thread id: %ld\n", pthread_self());
    
        for (int i = 0; i < 5; i++) {
            if (i == 2) {
                // int number = 1234;   //若是爲棧裏面的數據,則會組線程裏面,會崩潰或者失敗
                pthread_exit(&number);  //此處的地址,必須是指向堆或者全局變量
            }
    
            printf("child i = %d\n", i);
        }
    
        return NULL;
    }
    
  • 運行效果:


線程分離 pthread_detach():

在用 pthread_create 創建子線程的時候,第三個參數,是可以設置爲此屬性的;正常情況下,是由子線程死亡,是由父線程來釋放遺留的資源;但如果設置了此線程分離的屬性,那麼子線程是在創建的時候,就獨立於父線程,其死亡時候資源也是由自己來釋放。

int pthread_detach(pthread_t thread);
  • 調用該函數之後,就不在需要調用 pthread_jion() 了

殺死(取消)線程 pthread_cancel():

int pthread_cancel(pthread_t thread);
  • 注意:
    • 要殺死子線程對應的處理的函數的內部,必須做一次系統調用。
    • 系統調用函數有,eg: open,write, printf 等,這次都是最終會調用到系統層及的函數。
    • 不涉及到系統層級調用,eg: int a = 10;

判斷線程是否相等 pthread_equal():

是一個預留函數 ,通過線程號 判斷兩個線程是否相等;目前不需要使用該函數。若是以後線程變爲返回一個結構體。就可以用此預留函數(修改一下實現)來判斷兩個線程是否實現了。

int pthread_equal(pthread_t t1, pthread_t t2);

下載地址:

17_thread

歡迎 star 和 fork 這個系列的 linux 學習,附學習由淺入深的目錄。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章