QNX環境下多線程的編程

姓名:屈彥維

學號:16020610026

轉載自:http://lw.3edu.net/qrs/lw_184461.html

嵌牛導讀:qnx實時操作系統和多線程編程技術,包括線程間同步的方法、多線程程序的分析步驟、線程基本程序結構以及實用編譯方法。

嵌牛鼻子:qnx;多線程;同步;程序結構

嵌牛提問:QNX環境下多線程的編程相比其他類型的編程有何優勢?

嵌牛正文:




引言:qnx是由加拿大qnx軟件有限系統公司開發的一種多任務、分布式、可嵌入的實時操作系統。它有著輕巧的微內核,可以對進程進行全面的地址保護,可剪裁,模塊化程度高,實時性強,安全可靠。符合posix標準的api使它成為一個開放式互聯系統,便于與unix/linux系統的移植。qnx有著不同于unix或linux的模塊化設計思想,并不是unix或linux的一種演化,而是完全不同的一種全新的實時操作系統。由于其獨特的體系結構,qnx廣泛應用于嵌入式系統、機器人工程、工業控制、航空航天等各個領域。

在qnx中,線程是一個單一的控制執行流。從程序的最低層角度考慮,線程包括當前指令位置指針(也稱為計數器或pc)、棧頂指針(sp)和一些寄存器,而進程占據一定的內存空間,是一個或多個線程的集合。在同一進程中的線程共享許多資源,在qnx系統中共享的資源有:內存中儲存在棧區以外的變量——即非局部變量;信號處理器;信號忽略屏蔽字;通道——建立于服務器端;連接——建立于客戶端,而在不同進程中的線程除了cpu之外,幾乎不共享任何資源。當然qnx提供了shm_open()函數來使不同進程中的線程共享一段內存。

在早期的qnx版本如qnx4中,對于線程的支持是比較弱的,在當時的條件下,處理大型、復雜的并發多任務問題時,常常將問題分解為多個進程以降低問題的復雜性。而且qnx提供了與unix類似的進程間通訊ipc手段如消息、代理、信號燈等,功能也相對比較成熟、完善。1999年以后 qnx軟件公司推出了qnx/neutrino實時操作系統的neutrino2.0、neutrino6.0增加了對于posix線程的支持,標準的api不但使它易于擴展,而且也使得編寫多線程程序變得容易。由于線程具上下文較輕、切換較快、在創建多個線程時系統的開銷比較小、通訊手段靈活多樣、共享資源豐富等優點,在處理大型并發多任務問題時多線程有了明顯的優勢。qnx是搶先式多任務系統,這種系統決定了多個線程在訪問共享資源時線程執行的次序變得不可預期,所以線程間的同步就顯得極為重要。qnx提供了多種同步機制以保證多線程程序的安全、可靠。

1 qnx多線程庫函數簡介

qnx與linux不同,沒有單獨的線程庫,與線程有關的api是作為c語言庫函數的一部分使用的,頭文件是,同樣方便地提供線程的創建、終止和同步等功能。qnx不僅在c語言庫函數中提供了符合posix1003.1c標準的與線程相關的api,而且還提供了很多posix標準沒有的擴展功能,使得多線程編程變得更加容易。

1.1線程的創建、取消和終止

1.11線程的創建

qnx通過pthread_create()函數創建線程,api定義如下:

int pthread_create( pthread t* thread, const pthread attr t* attr, void* (*start routine)(void* ), void* arg );

pthread_create()創建的線程執行start routine() 函數,thread返回創建的線程描述符,而attr是創建線程時設置的線程屬性,arg可以作為任意類型的參數傳給start routine()函數。qnx對創建線程前需要設置的線程屬性進行了擴展,增加了posix標準無法設置的屬性如:可以禁止一個線程的取消(終止操作);可以設置一個線程的取消類型;可以指定當一個線程接到信號時,它如何操作。

1.12 線程的取消

qnx通過調用int pthread_cancel(pthread_t thread)函數取消由thread指定的線程,如果成功則返回0,否則為非0,成功并不意味著thread會終止,要視取消的狀態和類型而定。qnx提供了設定取消狀態和類型的api? pthread_setcancelstate()和pthread_setcanceltype(),取消的狀態有兩種:pthread_cancel_enable表示將線程設為取消狀態,pthread_cancel_disable表示忽略取消狀態;取消的類型也有兩種:

thread_cancel_deffered表示執行到取消點取消,pthread_cancel_asychronous表示立即取消。

1.13? 線程的終止

qnx中終止一個線程需要調用pthread exit(),其api定義:

void pthread exit( void* value ptr );

當一個線程在執行了start routine()函數后返回時,系統自動隱式調用pthread exit()使其退出,start routine()的返回值,作為線程的退出狀態。在一個線程中也可以顯式調用pthread exit()退出,對于單線程進程而言,調用pthread exit()與調用exit(0)是等效的。

1.2 線程的常用控制函數

pthread_self()

api:? pthread_t pthread_self(void);

說明:返回線程描述符,pthread_create()返回值相同。

pthread_equal()

api:? int pthread_equal(pthread_t t1,pthread_t t2);

說明:t1,t2為線程描述符,可調用pthread_self()和pthread_create()得到。此函數功能為比較兩個線程的描述符,不管線程描述符是否合法。如果返回值為非零說明兩個線程是同一線程,為零說明兩個線程不是同一線程。

pthread_join()

api:? int pthread_join(pthread_t thread, void** value_ptr);

說明:thread 為等待終止的目標線程,value_ptr為一指針,當值不為null時指向一個內存空間,這個空間用來存放目標線程傳給pthread_exit()的數據。調用pthread_join()的線程將被掛起,直到目標線程終止。一個線程僅允許唯一的線程使用pthread_join()等待它的終止,并且被等待的線程應該處于非detached狀態。qnx也提供了非posix的 pthread_timedjoin(),不同之處是線程在給定時間里沒有被join時,此函數會返回一個錯誤。

pthread_detach()

api:? int pthread_detach(pthread_t thread);

說明:此函數功能是將一給定線程thread分離,當一個出于分離狀態的線程終止時,線程擁有的所有系統資源將被立即釋放。

2 qnx線程的互斥和同步機制

線程間的互斥操作是指對于特定的一段代碼或一個變量,在程序運行時只能有一個線程對其進行操作,其他線程不能同時進入代碼或修改變量。線程間的同步操作是指若干個線程都等待某個事件的發生,當這個事件發生時,所有的線程同時進行下一步工作。為了防止競爭條件和數據被破壞的情況發生,qnx提供了多種互斥和同步機制,包括互斥體、條件變量、信號燈、屏障、讀/寫鎖、sleepon鎖等,其中最主要的是互斥體和條件變量,其余的同步機制都是由他們組合而成的,當然你也可以根據自己的要求構建自己的同步機制。

互斥體——qnx使用了互斥體來實現互斥操作,在初始化互斥體后,將給定的代碼或變量的前后進行加鎖、解鎖操作,線程在訪問之前要先得到互斥體,這樣就可以保證只有一個線程能訪問到代碼或變量,而其余的線程會處于阻塞狀態直到互斥體被釋放。這種機制保證了線程對資源訪問的互斥性,達到了對代碼或變量的保護。

條件變量——qnx的條件變量用來同步線程,所有線程都會等待一個條件變量可用,當條件滿足時,一個線程發出廣播或信號來同步所有的線程或某一線程。為了防止多個線程同時申請等待而產生競爭,條件變量通常要與互斥體聯合使用。

信號燈——qnx信號燈也是一種符合posix標準的的同步機制,它是由互斥體和條件變量結合一些數據構造而成的,qnx系統將其封裝在c語言庫函數中,頭文件是。它的功能很強大,可以允許多個線程訪問同一資源,可以通過設定燈值來限定線程的個數,燈值為一時它就是互斥體。

屏障——posix 1003.1j提議的內容,主要由互斥體、條件變量和計數器構造而成。作用是停止某些線程,當所要求的線程數量到達屏障時,所有的線程被允許繼續運行。屏障通常被用來確保某些并行算法中的所有合作線程在任何線程可以繼續運行以前到達算法中的一個特定點。

讀/寫鎖——posix 1003.1j提議的內容,主要由一個互斥體和兩個條件變量構造,兩個條件變量分別控制讀寫操作。讀/寫鎖允許多個線程同時讀數據,但是禁止任何線程修改正在被其他線程讀或修改的數據,也可以讓一個線程獨占寫訪問,但此時任何讀訪問的線程都不能繼續,直到讀/寫鎖被釋放,所以讀/寫鎖被用來保護經常需要讀但是通常不需要修改的。

sleepon鎖——qnx6所獨有的一種同步機制,由一個互斥體和一些數據構造而成,與條件變量相似但是用法比較簡單。它與條件變量的不同在于當有n個線程阻塞在m個對象的時候,如果用條件變量來同步時需要用到m個條件變量,而sleepon鎖為每個線程自動分配條件變量,只需要n個條件變量,使用合適可以節約系統資源。

3 多線程程序的設計分析與基本結構

3.1多線程程序的設計分析

1)確定完成任務所需的最少線程個數。

?多余的線程只會使程序的復雜性增加,出錯的可能性也隨之增加。設計程序時要遵循簡單、高效、安全的原則,如果用單線程能夠很好的完成任務,那么一定不要用多線程。

2)分析多線程需要共享的數據。

在多線程程序中常常需要共享一些數據,通常是一些全局變量,如果數據量很大可能需要開辟共享內存區。

3) 根據共享數據的特點選擇需要的保護機制。

多個線程需要寫操作的變量可以用互斥體保護,經常需要讀操作而很少進行寫操作的可以用讀/寫鎖保護等。

4) 分析工作線程需要訪問資源。

工作線程可能需要訪問硬件,等待硬件響應、可能需要訪問某一數據庫、也可能不訪問任何資源只是進行一些計算等等。這時需要考慮相應的同步機制,可以用條件變量結合互斥體,也可以用更為簡單的sleepon鎖。

5)進行線程的清理工作。

線程完成工作后可能會自動退出,也可能會阻塞在某處,甚至工作線程還沒完成工作的時候主線程已經退出,造成整個進程的結束,使程序失敗。有多種方法可以完成線程的清理工作,可以讓主線程調用pthread_join()函數清理工作線程,可以用屏障同步機制清理,也可以用條件變量來完成清理工作。

3.2多線程程序的基本結構

多線程編程的結構有很多種,但基本的編程結構起來有三種:流水線結構、工作組結構、客戶端/服務器結構。這三種結構可以以任意方式組合,來滿足實際工程的需求。

1) 流水線結構

在流水線結構中,需要處理的“數據”串行地被一組線程順序處理,每個線程依次在每個數據元素上執行一個特定的操作,完成操作后將結果傳遞給流水線中的下一個線程。如圖1所示。

2) 工作組結構

在工作組結構中,數據有一組線程分別獨立地處理,每個線程處理不同的部分。由于所有的工作線程在不同的數據部分上執行相同的操作,這種模式通常被稱為simd(單指令多數據流)并行處理。但是工作組中的線程可以不使用simd模型,他們可以在不同的數據上執行不同的操作。工作組結構是多線程程序應用較多的一種結構。如圖2所示

圖2 工作組結構

3) 客戶端/服務器結構

在客戶/服務器結構中,客戶請求服務器對一組數據執行某個操作。客戶端獨立地執行操作,而客戶端或者等待服務器執行的結果,或者并行執行另外的任務,在后面需要時在查找結果。這種結構又是一種對某些公共資源同步管理的簡單方式。如圖3

4 qnx neutrino內核對于線程功能的擴展

具有neutrino內核的qnx6操作系統對線程的功能進行了擴展,提供了一些posix標準沒有提供的功能。

1)posix標準規定使用互斥體的線程必須在同一進程內,作為擴展qnx支持在不同進程中的線程使用互斥體。如果在兩個進程間創建一塊共享內存,并在內存中初始化一個互斥體,那么兩個進程之間的線程可以用這個互斥體來進行同步操作,這是posix做不到的。

2) qnx操作系統還提出了一種獨特的“線程池”概念。當程序需要很多線程同時工作時,利用“線程池”可以將線程的個數限定在一定的范圍內。“高水位”、“低水位”的概念分別對應著程序中的最大線程數和最小線程數。當程序中線程數目小于“低水位”時,“線程池”會自動創建新的線程進行工作,當線程數目大于“高水位”時,“線程池”會“清除”多于的線程,以防止溢出。這樣程序將始終保持著一定數量的線程在工作,“線程池”特別適用客戶端/服務器結構,可以很好地保護服務器的資源。qnx提供了專門的程序庫來管理“線程池”頭文件是,相應的api主要有:thread_pool_create(),用于建立一個線程池,thread_pool_destroy()程序運行結束后用它來清除線程池,thread_pool_start()用來啟動一個線程池。

5 qnx系統下實用編譯方法

筆者編制了qnx環境下的通用makefile,用于編譯多線程程序,當然也適用于單線程程序的編譯,而這個makefile稍加改動便可以用于linux/unix系統中,筆者在redhat linux7下試驗通過。用法,首先將此makefile 和所要編譯的c/c++程序(支持多個c/c++程序)/頭文件放置于一個目錄中,在終端上鍵入make,此makefile將自動把所有相關源代碼連接編譯成名為go的可執行文件,要運行編譯好的程序,只需在終端上鍵入./go便可。在終端上鍵入make clean將把所有的編譯產生的臨時文件刪除,只留下原始文件和make文件,在終端上鍵入make depend將檢查文件的依賴

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容