pthread小結

来源:https://www.cnblogs.com/willhua/archive/2018/12/02/10053769.html
-Advertisement-
Play Games

"參考1 https://computing.llnl.gov/tutorials/pthreads/" "參考2 http://man7.org/linux/man pages/man7/pthreads.7.html" join 阻塞調用線程,直至指定pthread_t線程終止 在同一個線程中重 ...


參考1 https://computing.llnl.gov/tutorials/pthreads/
參考2 http://man7.org/linux/man-pages/man7/pthreads.7.html


join

  • int pthread_join(pthread_t, void**);阻塞調用線程,直至指定pthread_t線程終止
  • 在同一個線程中重覆調用join會導致錯誤
  • 在創建線程的時候可以指定要創建的線程是否joinable,如果是,則可以join,否則(即detached)不可以。一般預設都是joinable
  • POSIX指出線程should指定為joinable
  • 如果確定一個線程需要join,那麼最好明確指定該線程joinable,通過如下四步:
  1. Declare a pthread attribute variable of the pthread_attr_t data type
  2. Initialize the attribute variable with pthread_attr_init()
  3. Set the attribute detached status with pthread_attr_setdetachstate()
  4. When done, free library resources used by the attribute with pthread_attr_destroy()
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for(t=0; t<NUM_THREADS; t++) {
   printf("Main: creating thread %ld\n", t);
   rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t);  //一個attr可以給多個線程使用
   if (rc) {
      printf("ERROR; return code from pthread_create() is %d\n", rc);
      exit(-1);
      }
   }
pthread_attr_destroy(&attr);    //記得釋放資源。create執行完之後就可以釋放,而不用等待線程結束
  • 如果確定一個線程不需要joinable,那麼應該明確考慮設置屬性為detached
  • 通過pthread_detach()來設置線程為不可join,即使它被創建的時候被設置為joinable。這個動作不可逆

    stack

  • POSIX沒有規定創建的線程的stack大小是多少,這是由implementation決定的
  • pthread_attr_setstacksize可以用來設置需要的stack大小
  • pthread_attr_getstackaddrpthread_attr_setstackaddr可以用來設置stack需要放置到特定的記憶體區域
size_t stacksize;
pthread_attr_init(&attr);
pthread_attr_getstacksize (&attr, &stacksize);
printf("Default stack size = %li\n", stacksize);
size = 10000; //設置為10000bytes
pthread_attr_setstacksize (&attr, stacksize);
printf("set stack size = %li\n", stacksize);
pthread_create(&threads[t], &attr, dowork, (void *)t);

mutex

Creating and Destroying Mutexes

//destroy,成功則返回0
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//動態初始化,成功則返回0. 如果attr為NULL,那麼將使用預設屬性,相當於PTHREAD_MUTEX_INITIALIZER
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
//使用預設參數靜態初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//mutex屬性
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
  • 被destroy的mutex可以使用pthread_mutex_init重新初始化
  • destroy一個處於lock狀態的mutex,將會導致undefined行為
  • 只有mutex可以用來執行synchronization,用它的copies來執行lock,unlock和trylock將導致undefined
  • 不可以重覆初始化已經初始化了的mutex

    Locking and Unlocking Mutexes

//如果別的線程已經lock,那會一直阻塞當前線程直至獲得鎖
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
mutex類型 性質
PTHREAD_MUTEX_NORMAL 對mutex的重覆lock,即本線程已經lock了mutex,在沒有unlock之前又嘗試lock,將導致死鎖行為;unlock一個沒有被本線程lock或者沒有被任何線程lock的mutex,將導致未定義行為
PTHREAD_MUTEX_ERRORCHECK 嘗試重覆lock一個mutex將不會死鎖,而是返回一個錯誤值;unlock一個沒有被本線程lock或者沒有被任何線程lock的mutex,也會返回錯誤值
PTHREAD_MUTEX_RECURSIVE mutex可以被重覆lock。每次lock會增加相關計數,直至通過unlock使計數達到0時,才可以被別的線程lock;unlock一個沒有被本線程lock或者沒有被任何線程lock的mutex,也會返回錯誤值
PTHREAD_MUTEX_DEFAULT 重覆lock會導致未定義行為(NORMAL中會導致死鎖);unlock一個沒有被本線程lock或者沒有被任何線程lock的mutex,也將導致未定義行為。 不過,在NDK的定義中,直接把PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
  • pthread_mutex_trylockpthread_mutex_lock只有一點區別:如果當前mutex被任意線程lock,pthread_mutex_trylock都將會立刻返回。如果mutex是PTHREAD_MUTEX_RECURSIVE的,且mutex已經被當前調用線程lock,pthread_mutex_trylock也同樣會導致計數增一,並返回success。
  • 如果正在等待lock的線程收到了一個signal,當其從signal handler返回之後,會繼續等待lock,就和signal沒有發生一樣
  • 除非使用了 thread priority scheduling,否則多個正在等待lock的線程獲得lock的情況可能多少有點random
  • 如果成功,這三個函數都是返回0,否則返回相應的error

Condition Variables

  • mutex通過控制對數據的訪問許可權來達到同步;而condition variables則基於數據的值來控制同步
  • 如果不使用condition variable,線程想要檢查某個條件則只能通過輪詢的方式,這將非常resource consuming,因為這期間線程將一直active。而使用condition variable則將在不使用輪詢的情況下實現此目標
  • condition variable 經常和mutex一起使用

    Creating and Destroying Condition Variables

int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

int pthread_condattr_destroy(pthread_condattr_t *attr);
int pthread_condattr_init(pthread_condattr_t *attr);
  • destory正由某個線程用於block的cv將導致未定義行為
  • 只有cv自己能夠用於同步,任何基於它的copies調用pthread_cond_wait(), pthread_cond_timedwait(), pthread_cond_signal(), pthread_cond_broadcast(), pthread_cond_destroy()都會產生未定義行為
  • 初始化一個已經初始化的cv會導致未定義行為;已經destory的cv可以再次初始化;

Waiting and Signaling on Condition Variables

一般使用流程:
FueOfg.jpg

int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, 
                            const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
  • 這兩個函數將導致調用線程block on the condition variable, 並且需要傳入一個由調用線程lock了的mutex,否則導致未定義行為
  • 如果在wait之前,沒有明確lock對應mutex,可能並不會導致block
  • 這兩個函數會原子的unlock the mutex,並且導致調用線程block on the condition variable。這裡的原子的意味著:只要其他線程lock了這個mutex,那麼這個線程對pthread_cond_broadcast()pthread_cond_signal()的調用都會產生調用wait的線程已經blocked on the condition variable的效果
  • 只要這兩個函數返回,那麼調用線程就已經lock了這個mutex
  • 虛假喚醒Spurious wakeups 可能會產生,而且這並不違反標準,所以,即使調用線程被喚醒,也不意味著對某個值做出某種保證,應該再次確認條件是否真的滿足了。同時,考慮到線程之間的競爭,pthread_cond_timedwait由於超時返回之後,條件也可能已經滿足。總之。任何時候wait返回,都需要重新評估條件是否滿足,這點非常重要
  • 一旦線程waits on the condition variable,那麼這個cv就和相應的mutex綁定了,在wait返回之前,不能再使用另外的mutex來調用wait,這會導致未定義行為
  • condition wait是一個cancellation point未明白
  • 假設一個由於wait調用而block線程由於被canceled而unblocked,這個不會consume任何condition signal。
  • pthread_cond_timedwait()pthread_cond_wait()是equivalent的,除了:當signaled或者broadcasted超過指定時間,pthread_cond_timedwait()就會返回返回error。同時,cv還可以支持 Clock Selection,選擇不同的Clock來measure指定的時間
  • 當cv wait期間,一個signal產生了,那麼cv可能會繼續wait就像沒有中斷一樣,或者這會形成一個spurious wakeup,返回0.
    推薦使用while迴圈替代if語句來檢查當前條件是否真的滿足,有如下三點好處:
  1. 如果有多個線程都是在wait相同過的wake up signal,那麼當其他任意一個被waked up之後,他們都有可能更改條件值,而導致條件不滿足
  2. 線程可能會因為程式bug而收到一個signal
  3. Pthreads library被容許產生虛假喚醒,而且這並不違反標準
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
  • 當多於一個線程在wait的時候,應該使用pthread_cond_broadcast()
  • 在signal之前,應該先lock對應mutex,然後在signal之後,應該unlock對應mutex。如果忘記了unlock,那麼相應的wait線程會繼續blocked,因為他們無法獲得lock

結束線程

有:

  • pthread_cancel
  • pthread_exit
  • pthread_kill
    參考https://www.cnblogs.com/biyeymyhjob/archive/2012/10/11/2720377.html
    ---

    其他函數

    pthread_self

    pthread_t pthread_self(void);返回調用線程的thread id

    pthread_equal

    int pthread_equal(pthread_t t1, pthread_t t2);比較兩個ID是否相等,如果相等則返回not-zero value不相等則返回0。由於pthread_t結果opaque,所以不應該用==來比較

    pthread_once

    int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));:在進程中,任何首次調用這個函數的線程,在pthread_once_t once_control = PTHREAD_ONCE_INIT的時候,會調用init_routine程式。並且當此函數返回的時候,init_routine已經執行完了(這裡沒有說init_routine會阻塞調用線程,可能考慮的是,當線程A已經調用init_routine,而另外一個線程B也調用了pthread_once,那麼是否B也會等待A調用的init_routine執行完畢?)。如果成功完成,則pthread_once返回0。如果once_control參數不是PTHREAD_ONCE_INIT,那麼行為將是undefined。在LinuxThreads中:

在LinuxThreads中,實際"一次性函數"的執行狀態有三種:NEVER(0)、IN_PROGRESS(1)、DONE (2),如果once初值設為1,則由於所有pthread_once()都必須等待其中一個激發"已執行一次"信號,因此所有pthread_once ()都會陷入永久的等待中;如果設為2,則表示該函數已執行過一次,從而所有pthread_once()都會立即返回0。

這個函數在當無法編輯進程的main函數,比如寫一個庫的時候,就很有用。
TODO:如果多個線程使用的init_routine不相同怎麼辦?或者比如自己開發庫,但是user的main中已經使用不同的init_routine調用了pthread_once,那麼會是什麼結果?



您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、if語句if 語句基本用法: 其中,表達式可以是一個單純的布爾值或變數,也可以是比較表達式或邏輯表達式,如果表達式為真,則執行“語句塊”;如果表達式的值為假,就跳 過“語句塊”,繼續執行後面的語句。 2、if…else語句if…else 語句基本用法: 使用 if…else 語句時,表達式可以是 ...
  • 總體原則:命名一定要體現其在程式中的作用; Camel命名法:第一個單詞的首字母小寫,其餘每個單詞的首字母大寫;多用給變數或者欄位命名;給欄位命名必須以下劃線開始; Pascal命名法:每個單詞的首字母都大寫,其餘字母小寫;適用於方法名、類名、屬性名等; ...
  • 一. 起始 去年.NetCore2.0的發佈,公司決定新項目採用.NetCore開發,當作試驗。但是問題在於當前公司內部使用的RPC服務為Thrift v0.9 + zookeeper版本,經過個性化定製,支持了非同步,但也因為如此,這麼多年來一直沒有去升級,導致遷移工作很複雜(歷史遺留項目太多,有各 ...
  • 前言 曾有做過一個產品,有一個功能是視頻監控模塊,視頻監控首先想到的是視頻多畫面切換功能,由於前端是用WPF開發的,所以當時就做了一個多畫面切換組件,效果如下: 功能設計前提: 由於要使用海康大華天地偉業等視頻廠家的視頻,對接的方式是通過各個廠家提供的SDK(官網下載),由於播放視頻的時候需要傳遞控 ...
  • .NET 術語 1. AOT 預編譯器。與 JIT 類似,此編譯器還可將 IL 轉換為機器代碼。 與 JIT 編譯相比,AOT 編譯在應用程式執行前進行並且通常在不同電腦上執行。 由於在運行時 AOT 工具鏈不編譯,因此它們不需要最大程度地減少編譯所花費的時間。 這意味著它們可花更多的時間進行優化 ...
  • 1 .gz 1)壓縮 2)解壓縮: 註意:不能壓縮目錄!支持批量壓縮,源文件被替換成.gz結尾的文件。 2 .bz2 1)壓縮 2)解壓縮: 3)強制壓縮: 註意:不能壓縮目錄!支持批量壓縮,源文件被替換成.bz2結尾的文件。 3 .zip 1)壓縮 2)解壓縮 註意:可以壓縮目錄!支持批量壓縮,源 ...
  • VMware 安裝提示缺少MicrosoftRuntime DLL 問題解決辦法 剛剛安裝VMware失敗了試了好多辦法,在這總結一下。 下麵是程式的截圖 這是報錯信息 網上的解決方法: 當出現安裝失敗的提示時,不要將界面關閉,然後在運行視窗輸入 %temp% 然後會進如文件夾, 在文件夾里找到類似 ...
  • 1. 主機規劃 主機名稱 IP地址 操作系統 部署軟體 運行進程 備註 mini01 172.16.1.11【內網】 10.0.0.11 【外網】 CentOS 7.5 Jdk-8、zookeeper-3.4.5、Hadoop2.7.6、hbase-2.0.2、kafka_2.11-2.0.0、sp ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...