日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux线程(二)

發布時間:2024/4/11 linux 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux线程(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

linux線程(二)

文章目錄

  • linux線程(二)
    • 一、線程終止
    • 二、線程等待
    • 三、線程分離
    • 四、線程互斥

一、線程終止

  • 1.pthread_exit函數:

只需終止某個線程而不需要終止整個進程的三個方法:

  • 從線程函數return,這種方法對主線程不適合,從main函數的return,相當于調用exit函數
  • 線程可以調用pthread_exit來終止自己
  • 一個線程可以調用pthread_cancel函數終止同一個進程中的另一個線程
void pthread_exit(void *retval);
  • 作用:終止線程自己
  • 參數:void *retval:不要指向一個局部變量,子線程可以通過pthread_exit傳遞一個返回值,而主線程通過pthread_join獲得該返回值,從而判斷該子線程的退出是正常還是異常。
  • 返回值:無反回值,和進程一樣,線程結束就無法返回到它的調用者(自己都被自己給干掉了,怎么返回給自己)
  • 注意??:pthread_exit或者return返回的指針所指向的內存單元必須是全局變量或者是在堆上申請的空間,不能是線程函數內部棧上分配的,因為其他線程得到這個返回指針的時候線程函數已經退出了
  • 2.pthread_cancel函數
int pthread_cancel(pthread_t thread)
  • 功能:取消一個執行中的線程
  • 參數:thread:線程ID
  • 返回值:成功返回0.失敗返回錯誤碼

二、線程等待

  • 線程等待原因:
  • 已經退出的線程,其空間是沒有被釋放的,仍然在進程的地址空間中,即釋放資源,防止內存泄漏
  • 創建新的線程不會復用剛才退出線程的地址空間
  • 2.pthread_join函數
int pthread_join(pthread_t thread, void **retval);
  • 功能:等待線程的結束
  • 參數:
pthread_t thread:線程IDvoid **retval:它指向一個指針指向線程的返回值,輸出型參數,一般填NULL
  • 注意??:調用該函數的線程將被掛起等待,直到id為指定的線程結束終止,thread線程以不同的方法終止,通過pthread_join得到的終止狀態是不同的,總結如下:
    a.如果thread線程是通過return返回,retval所指向的單元里存放的是thread線程函數的返回值
    b.如果thread線程被別的線程調用pthread_cancel函數異常終止掉,retval所指向的單元里存放到是常數PTHREAD_CANCELED
    c.如果thread線程是調用pthread_exit函數終止的,retval所指向的單元里存放是傳給pthread_exit函數的參數,(即這里的retval參數是和pthread_exit函數的參數是相關聯的)
    d.如果對thread線程終止狀態不感興趣直接傳NULL即可。

    通過代碼驗證:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> void *thread1( void *arg ) {printf("thread 1 returning ... \n");int *p = (int*)malloc(sizeof(int));*p = 1;return (void*)p; } void *thread2( void *arg ) {printf("thread 2 exiting ...\n");int *p = (int*)malloc(sizeof(int));*p = 2;pthread_exit((void*)p); } void *thread3( void *arg ) {while ( 1 ){ //printf("thread 3 is running ...\n");sleep(1);} return NULL; } int main( void ) {pthread_t tid;void *ret;// thread 1 return pthread_create(&tid, NULL, thread1, NULL);pthread_join(tid, &ret);printf("thread return, thread id %X, return code:%d\n", tid, *(int*)ret);free(ret);// thread 2 exitpthread_create(&tid, NULL, thread2, NULL);pthread_join(tid, &ret);printf("thread return, thread id %X, return code:%d\n", tid, *(int*)ret);free(ret);// thread 3 cancel by otherpthread_create(&tid, NULL, thread3, NULL);sleep(3);pthread_cancel(tid);pthread_join(tid, &ret);if ( ret == PTHREAD_CANCELED )printf("thread return, thread id %X, return code:PTHREAD_CANCELED\n", tid);elseprintf("thread return, thread id %X, return code:NULL\n", tid); }


通過結果充分驗證上面的結論

三、線程分離

  • 默認情況下,新創建的線程是joinable的,線程退出后,需要對其進行pthread_join操作,否則無法釋放線程自己的空間上的資源,從而導致內存泄漏
  • 如果不關心線程的返回值,join是一種負擔,這個時候,我們可以告訴系統,當線程退出時自動釋放線程的資源
int pthread_detach(pthread_t thread)
  • 功能:可以是線程組內其他線程對目標線程進行分離,也可以是線程自己分離
  • 參數:thread:線程ID
  • 返回值:若成功則返回0,若出錯則返回錯誤碼
  • 注意??:joinable和thread_detach是沖突的,一個線程不能即時joinable的又是分離的
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> void *thread_run( void * arg ) {pthread_detach(pthread_self());printf("%s\n", (char*)arg);return NULL; } int main( void ) {pthread_t tid;if ( pthread_create(&tid, NULL, thread_run, (void*)"thread1 run...") != 0 ) {printf("create thread error\n");return 1;} int ret = 0;sleep(1);//很重要,要讓線程先分離,再等待if ( pthread_join(tid, NULL ) == 0 ) {printf("pthread wait success\n");ret = 0;} else {printf("pthread wait failed\n");ret = 1;} return ret; }

四、線程互斥

  • 1.線程互斥相關概念
  • 臨界資源:多線程執行流中共享的資源就叫臨界資源(如多個線程共同訪問一個全局變量,那個被訪問的全局變量就是臨界資源)
  • 臨界區:每個線程內部,用來訪問臨界資源的代碼就是臨界區(如上面的例子,訪問全局變量的代碼就是臨界區)
  • 互斥:任何時候,互斥保證了有且僅有一個執行流進入臨界區,訪問臨界資源,通常對臨界資源起保護作用。互斥機制也是解決線程不安全問題的方法
  • 互斥機制的使用:a.先加鎖 b.執行臨界區代碼 c.釋放鎖
  • 注意,在互斥機制下,同一時刻只能有一個線程獲取到鎖,只有獲取到鎖的線程才能執行臨界區代碼,訪問臨界資源,其他線程只能等待獲得鎖的線程釋放鎖
  • 原子性:不會被任何調度機制打斷的操作,該操作只有兩個狀態,要么完成,要么未完成(相當于是最小的幀操作,沒有任何機制可以打斷的操作)
  • 2.互斥量:mutex
  • 大部分情況,線程使用的數據都是局部數據,變量的地址空間在線程棧空間內,這種情況,變量歸屬單個線程,其他線程無法獲取到這種變量
  • 有時候,很多變量都需要在線程間共享,這樣的變量稱為共享變量,可以通過數據的共享,完成線程之間的交互
  • 但是,多個線程并發的操作共享變量,會帶來很多問題
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h>int ticket = 100; void *route(void *arg) {char *id = (char*)arg; while ( 1 ) {if ( ticket > 0 ) {usleep(1000);printf("%s sells ticket:%d\n", id, ticket);ticket--;} else {break;}} } int main( void ) {pthread_t t1, t2, t3, t4;pthread_create(&t1, NULL, route, "thread 1");pthread_create(&t2, NULL, route, "thread 2");pthread_create(&t3, NULL, route, "thread 3");pthread_create(&t4, NULL, route, "thread 4");pthread_join(t1, NULL);pthread_join(t2, NULL);pthread_join(t3, NULL);pthread_join(t4, NULL); }



根據上面的代碼,發現沒有正確的獲取到我們想要的結果,為什么呢?

  • if 語句判斷條件為真以后,代碼可以并發的切換到其他線程
  • usleep這個模擬漫長業務的過程,在這個漫長的業務過程中,可能有很多個線程會進入該代碼段
  • –ticket操作本身就不是一個原子操作
  • –操作并不是原子操作,而是對應三條匯編指令
  • load:將共享變量ticket從內存加載到寄存器中
  • update: 更新寄存器里面的值,執行-1操作
  • store:將新值,從寄存器寫回共享變量ticket的內存地址

解決辦法請看Linux線程(三)

總結

以上是生活随笔為你收集整理的Linux线程(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。