Linux 的多執行緒程式設計的高效開發經驗

2021-04-27 09:07:33 字數 3224 閱讀 1476

本文中我們針對 linux 上多執行緒程式設計的主要特性總結出 5 條經驗,用以改善 linux 多執行緒程式設計的習慣和避免其中的開發陷阱。在本文中,我們穿插一些 windows 的程式設計用例用以對比 linux 特性,以加深讀者印象。

背景

linux 平台上的多執行緒程式開發相對應其他平台(比如 windows)的多執行緒 api 有一些細微和隱晦的差別。不注意這些 linux 上的一些開發陷阱,常常會導致程式問題不窮,死鎖不斷。本文中我們從 5 個方面總結出 linux 多執行緒程式設計上的問題,並分別引出相關改善的開發經驗,用以避免這些的陷阱。我們希望這些經驗可以幫助讀者們能更好更快的熟悉 linux 平台的多執行緒程式設計。

我們假設讀者都已經很熟悉 linux 平台上基本的執行緒程式設計的 pthread 庫 api 。其他的第三方用以執行緒程式設計的庫,如 boost,將不會在本文中提及。本文中主要涉及的題材包括執行緒開發中的執行緒管理,互斥變數,條件變數等。程序概念將不會在本文中涉及。

linux 上線程開發 api 的概要介紹

多執行緒開發在 linux 平台上已經有成熟的 pthread 庫支援。其涉及的多執行緒開發的最基本概念主要包含三點:執行緒,互斥鎖,條件。其中,執行緒操作又分執行緒的建立,退出,等待 3 種。互斥鎖則包括 4 種操作,分別是建立,銷毀,加鎖和解鎖。條件操作有 5 種操作:建立,銷毀,觸發,廣播和等待。其他的一些執行緒擴充套件概念,如訊號燈等,都可以通過上面的三個基本元素的基本操作封裝出來。

執行緒,互斥鎖,條件在 linux 平台上對應的 api 可以用表 1 歸納。為了方便熟悉 windows 執行緒程式設計的讀者熟悉 linux 多執行緒開發的 api,我們在表中同時也列出 windows sdk 庫中所對應的 api 名稱。

表 1. 執行緒函式列表物件

操作linux pthread api

windows sdk 庫對應 api

執行緒建立

pthread_create

createthread

退出pthread_exit

threadexit

等待pthread_join

waitforsingleobject

互斥鎖建立

pthread_mutex_init

createmutex

銷毀pthread_mutex_destroy

closehandle

加鎖pthread_mutex_lock

waitforsingleobject

解鎖pthread_mutex_unlock

releasemutex

條件建立

pthread_cond_init

createevent

銷毀pthread_cond_destroy

closehandle

觸發pthread_cond_signal

setevent

廣播pthread_cond_broadcast

setevent / resetevent

等待pthread_cond_wait / pthread_cond_timedwait

singleobjectandwait

多執行緒開發在 linux 平台上已經有成熟的 pthread 庫支援。其涉及的多執行緒開發的最基本概念主要包含三點:執行緒,互斥鎖,條件。其中,執行緒操作又分執行緒的建立,退出,等待 3 種。互斥鎖則包括 4 種操作,分別是建立,銷毀,加鎖和解鎖。條件操作有 5 種操作:建立,銷毀,觸發,廣播和等待。其他的一些執行緒擴充套件概念,如訊號燈等,都可以通過上面的三個基本元素的基本操作封裝出來。

linux 執行緒程式設計中的 5 條經驗

盡量設定 recursive 屬性以初始化 linux 的互斥變數

互斥鎖是多執行緒程式設計中基本的概念,在開發中被廣泛使用。其呼叫次序層次清晰簡單:建鎖,加鎖,解鎖,銷毀鎖。但是需要注意的是,與諸如 windows 平台的互斥變數不同,在預設情況下,linux 下的同一執行緒無法對同一互斥鎖進行遞迴加速,否則將發生死鎖。

所謂遞迴加鎖,就是在同一執行緒中試圖對互斥鎖進行兩次或兩次以上的行為。其場景在 linux 平台上的**可由清單 1 所示。

清單 1. linux 重複對互斥鎖加鎖例項

// 通過預設條件建鎖

pthread_mutex_t *themutex = new pthread_mutex_t;

pthread_mutexattr_t attr;

pthread_mutexattr_init(&attr);

pthread_mutex_init(themutex,&attr);

pthread_mutexattr_destroy(&attr);

// 遞迴加鎖

pthread_mutex_lock (themutex);

pthread_mutex_lock (themutex);

pthread_mutex_unlock (themutex);

pthread_mutex_unlock (themutex);

在以上**場景中,問題將出現在第二次加鎖操作。由於在預設情況下,linux 不允許同一執行緒遞迴加鎖,因此在第二次加鎖操作時執行緒將出現死鎖。

linux 互斥變數這種奇怪的行為或許對於特定的某些場景會所有用處,但是對於大多數情況下看起來更像是程式的乙個 bug 。畢竟,在同一執行緒中對同一互斥鎖進行遞迴加鎖在尤其是二次開發中經常會需要。

這個問題與互斥鎖的中的預設 recursive 屬性有關。解決問題的方法就是顯式地在互斥變數初始化時將設定起 recursive 屬性。基於此,以上**其實稍作修改就可以很好的執行,只需要在初始化鎖的時候加設定乙個屬性。請看清單 2 。

清單 2. 設定互斥鎖 recursive 屬性例項

pthread_mutexattr_init(&attr); 

// 設定 recursive 屬性

pthread_mutexattr_settype(&attr,pthread_mutex_recursive_np);

pthread_mutex_init(themutex,&attr);

因此,建議盡量設定 recursive 屬性以初始化 linux 的互斥鎖,這樣既可以解決同一執行緒遞迴加鎖的問題,又可以避免很多情況下死鎖的發生。這樣做還有乙個額外的好處,就是可以讓 windows 和 linux 下讓鎖的表現統一。

Linux多執行緒程式設計 執行緒的同步

posix訊號量 posix訊號量不同於ipc中的訊號量 常用的posix訊號量函式 include int sem init sem t sem,int pshared,unsigned int value 初始化乙個訊號量,pshared引數指定訊號量的型別,若為0,表示訊號量為當前程序的區域性...

簡單的Linux多執行緒程式設計

最近在實習的公司做乙個ros系統,有個部分需要控制電機,以及分析電機碼盤給上來的資料,用的是串列埠通訊。由於碼盤給上來的資料時間是不固定的,下放命令的時間也是不固定的,所以只能做成非同步通訊的形式。所以就需要用到多執行緒程式設計了。程式語言是c,但由於另乙個部分是企業提供的,c 形式,用到了很多類,...

Linux下的多執行緒程式設計

執行緒是作業系統能夠進行排程運算的最小單位,它被包含在程序之中,是程序中的實際運作單位。一條執行緒指的是程序中乙個單一順序的控制流,乙個程序可以併發多個執行緒,每條執行緒執行不同的任務。include intpthread create pthread t pthread,const pthread...