QNX環(huán)境下多線(xiàn)程編程

發(fā)布時(shí)間:2010-11-16 15:40    發(fā)布者:eetech
關(guān)鍵詞: QNX , 編程 , 多線(xiàn)程 , 環(huán)境
紹了QNX實(shí)時(shí)操作系統和多線(xiàn)程編程技術(shù),包括線(xiàn)程間同步的方法、多線(xiàn)程程序的分析步驟、線(xiàn)程基本程序結構以及實(shí)用編譯方法。  

QNX是由加拿大QNX軟件有限系統公司開(kāi)發(fā)的一種多任務(wù)、分布式、可嵌入的實(shí)時(shí)操作系統。它有著(zhù)輕巧的微內核,可以對進(jìn)程進(jìn)行全面的地址保護,可剪裁,模塊化程度高,實(shí)時(shí)性強,安全可靠。符合POSIX標準的API使它成為一個(gè)開(kāi)放式互聯(lián)系統,便于與UNIX/LINUX系統的移植。QNX有著(zhù)不同于UNIX或LINUX的模塊化設計思想,并不是UNIX或LINUX的一種演化,而是完全不同的一種全新的實(shí)時(shí)操作系統。由于其獨特的體系結構,QNX廣泛應用于嵌入式系統、機器人工程、工業(yè)控制、航空航天等各個(gè)領(lǐng)域。  

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

在早期的QNX版本如QNX4中,對于線(xiàn)程的支持是比較弱的,在當時(shí)的條件下,處理大型、復雜的并發(fā)多任務(wù)問(wèn)題時(shí),常常將問(wèn)題分解為多個(gè)進(jìn)程以降低問(wèn)題的復雜性。而且QNX提供了與UNIX類(lèi)似的進(jìn)程間通訊IPC手段如消息、代理、信號燈等,功能也相對比較成熟、完善。1999年以后 QNX軟件公司推出了QNX/Neutrino實(shí)時(shí)操作系統的Neutrino2.0、Neutrino6.0增加了對于POSIX線(xiàn)程的支持,標準的API不但使它易于擴展,而且也使得編寫(xiě)多線(xiàn)程程序變得容易。由于線(xiàn)程具上下文較輕、切換較快、在創(chuàng )建多個(gè)線(xiàn)程時(shí)系統的開(kāi)銷(xiāo)比較小、通訊手段靈活多樣、共享資源豐富等優(yōu)點(diǎn),在處理大型并發(fā)多任務(wù)問(wèn)題時(shí)多線(xiàn)程有了明顯的優(yōu)勢。QNX是搶先式多任務(wù)系統,這種系統決定了多個(gè)線(xiàn)程在訪(fǎng)問(wèn)共享資源時(shí)線(xiàn)程執行的次序變得不可預期,所以線(xiàn)程間的同步就顯得極為重要。QNX提供了多種同步機制以保證多線(xiàn)程程序的安全、可靠。  

1 QNX多線(xiàn)程庫函數簡(jiǎn)介  

QNX與LINUX不同,沒(méi)有單獨的線(xiàn)程庫,與線(xiàn)程有關(guān)的API是作為C語(yǔ)言庫函數的一部分使用的,頭文件是,同樣方便地提供線(xiàn)程的創(chuàng )建、終止和同步等功能。QNX不僅在C語(yǔ)言庫函數中提供了符合POSIX1003.1c標準的與線(xiàn)程相關(guān)的API,而且還提供了很多POSIX標準沒(méi)有的擴展功能,使得多線(xiàn)程編程變得更加容易。  

1.1線(xiàn)程的創(chuàng )建、取消和終止

1.11線(xiàn)程的創(chuàng )建  

QNX通過(guò)pthread_create()函數創(chuàng )建線(xiàn)程,API定義如下:  

int pthread_create( pthread t* thread, const pthread attr t* attr, void* (*start routine)(void* ), void* arg );  
pthread_create()創(chuàng )建的線(xiàn)程執行start routine() 函數,thread返回創(chuàng )建的線(xiàn)程描述符,而attr是創(chuàng )建線(xiàn)程時(shí)設置的線(xiàn)程屬性,arg可以作為任意類(lèi)型的參數傳給start routine()函數。QNX對創(chuàng )建線(xiàn)程前需要設置的線(xiàn)程屬性進(jìn)行了擴展,增加了POSIX標準無(wú)法設置的屬性如:可以禁止一個(gè)線(xiàn)程的取消(終止操作);可以設置一個(gè)線(xiàn)程的取消類(lèi)型;可以指定當一個(gè)線(xiàn)程接到信號時(shí),它如何操作。  

1.12 線(xiàn)程的取消  

QNX通過(guò)調用int pthread_cancel(pthread_t thread)函數取消由thread指定的線(xiàn)程,如果成功則返回0,否則為非0,成功并不意味著(zhù)thread會(huì )終止,要視取消的狀態(tài)和類(lèi)型而定。QNX提供了設定取消狀態(tài)和類(lèi)型的API  pthread_setcancelstate()和pthread_setcanceltype(),取消的狀態(tài)有兩種:PTHREAD_CANCEL_ENABLE表示將線(xiàn)程設為取消狀態(tài),PTHREAD_CANCEL_DISABLE表示忽略取消狀態(tài);取消的類(lèi)型也有兩種:  

THREAD_CANCEL_DEFFERED表示執行到取消點(diǎn)取消,PTHREAD_CANCEL_ASYCHRONOUS表示立即取消。  

1.13  線(xiàn)程的終止  

QNX中終止一個(gè)線(xiàn)程需要調用pthread exit(),其API定義:

void pthread exit( void* value ptr );  

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

1.2 線(xiàn)程的常用控制函數  

pthread_self()
API:  pthread_t pthread_self(void);
說(shuō)明:返回線(xiàn)程描述符,pthread_create()返回值相同。
pthread_equal()
API:  int pthread_equal(pthread_t t1,pthread_t t2);  
說(shuō)明:t1,t2為線(xiàn)程描述符,可調用pthread_self()和pthread_create()得到。此函數功能為比較兩個(gè)線(xiàn)程的描述符,不管線(xiàn)程描述符是否合法。如果返回值為非零說(shuō)明兩個(gè)線(xiàn)程是同一線(xiàn)程,為零說(shuō)明兩個(gè)線(xiàn)程不是同一線(xiàn)程。  
pthread_join()
API:  int pthread_join(pthread_t thread, void** value_ptr);  
說(shuō)明:thread 為等待終止的目標線(xiàn)程,value_ptr為一指針,當值不為NULL時(shí)指向一個(gè)內存空間,這個(gè)空間用來(lái)存放目標線(xiàn)程傳給pthread_exit()的數據。調用pthread_join()的線(xiàn)程將被掛起,直到目標線(xiàn)程終止。一個(gè)線(xiàn)程僅允許唯一的線(xiàn)程使用pthread_join()等待它的終止,并且被等待的線(xiàn)程應該處于非DETACHED狀態(tài)。QNX也提供了非POSIX的 pthread_timedjoin(),不同之處是線(xiàn)程在給定時(shí)間里沒(méi)有被join時(shí),此函數會(huì )返回一個(gè)錯誤信息。  
pthread_detach()
API:  int pthread_detach(pthread_t thread);  
說(shuō)明:此函數功能是將一給定線(xiàn)程thread分離,當一個(gè)出于分離狀態(tài)的線(xiàn)程終止時(shí),線(xiàn)程擁有的所有系統資源將被立即釋放。  

2 QNX線(xiàn)程的互斥和同步機制  

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

互斥體——QNX使用了互斥體來(lái)實(shí)現互斥操作,在初始化互斥體后,將給定的代碼或變量的前后進(jìn)行加鎖、解鎖操作,線(xiàn)程在訪(fǎng)問(wèn)之前要先得到互斥體,這樣就可以保證只有一個(gè)線(xiàn)程能訪(fǎng)問(wèn)到代碼或變量,而其余的線(xiàn)程會(huì )處于阻塞狀態(tài)直到互斥體被釋放。這種機制保證了線(xiàn)程對資源訪(fǎng)問(wèn)的互斥性,達到了對代碼或變量的保護。  

條件變量——QNX的條件變量用來(lái)同步線(xiàn)程,所有線(xiàn)程都會(huì )等待一個(gè)條件變量可用,當條件滿(mǎn)足時(shí),一個(gè)線(xiàn)程發(fā)出廣播或信號來(lái)同步所有的線(xiàn)程或某一線(xiàn)程。為了防止多個(gè)線(xiàn)程同時(shí)申請等待而產(chǎn)生競爭,條件變量通常要與互斥體聯(lián)合使用。  

信號燈——QNX信號燈也是一種符合POSIX標準的的同步機制,它是由互斥體和條件變量結合一些數據構造而成的,QNX系統將其封裝在C語(yǔ)言庫函數中,頭文件是。它的功能很強大,可以允許多個(gè)線(xiàn)程訪(fǎng)問(wèn)同一資源,可以通過(guò)設定燈值來(lái)限定線(xiàn)程的個(gè)數,燈值為一時(shí)它就是互斥體。  

屏障——POSIX 1003.1j提議的內容,主要由互斥體、條件變量和計數器構造而成。作用是停止某些線(xiàn)程,當所要求的線(xiàn)程數量到達屏障時(shí),所有的線(xiàn)程被允許繼續運行。屏障通常被用來(lái)確保某些并行算法中的所有合作線(xiàn)程在任何線(xiàn)程可以繼續運行以前到達算法中的一個(gè)特定點(diǎn)。  
讀/寫(xiě)鎖——POSIX 1003.1j提議的內容,主要由一個(gè)互斥體和兩個(gè)條件變量構造,兩個(gè)條件變量分別控制讀寫(xiě)操作。讀/寫(xiě)鎖允許多個(gè)線(xiàn)程同時(shí)讀數據,但是禁止任何線(xiàn)程修改正在被其他線(xiàn)程讀或修改的數據,也可以讓一個(gè)線(xiàn)程獨占寫(xiě)訪(fǎng)問(wèn),但此時(shí)任何讀訪(fǎng)問(wèn)的線(xiàn)程都不能繼續,直到讀/寫(xiě)鎖被釋放,所以讀/寫(xiě)鎖被用來(lái)保護經(jīng)常需要讀但是通常不需要修改的信息。  

Sleepon鎖——QNX6所獨有的一種同步機制,由一個(gè)互斥體和一些數據構造而成,與條件變量相似但是用法比較簡(jiǎn)單。它與條件變量的不同在于當有N個(gè)線(xiàn)程阻塞在M個(gè)對象的時(shí)候,如果用條件變量來(lái)同步時(shí)需要用到M個(gè)條件變量,而sleepon鎖為每個(gè)線(xiàn)程自動(dòng)分配條件變量,只需要N個(gè)條件變量,使用合適可以節約系統資源。  

3 多線(xiàn)程程序的設計分析與基本結構  

3.1 多線(xiàn)程程序的設計分析

1)確定完成任務(wù)所需的最少線(xiàn)程個(gè)數。  

多余的線(xiàn)程只會(huì )使程序的復雜性增加,出錯的可能性也隨之增加。設計程序時(shí)要遵循簡(jiǎn)單、高效、安全的原則,如果用單線(xiàn)程能夠很好的完成任務(wù),那么一定不要用多線(xiàn)程。  

2)分析多線(xiàn)程需要共享的數據。  

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

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

多個(gè)線(xiàn)程需要寫(xiě)操作的變量可以用互斥體保護,經(jīng)常需要讀操作而很少進(jìn)行寫(xiě)操作的可以用讀/寫(xiě)鎖保護等。  

4) 分析工作線(xiàn)程需要訪(fǎng)問(wèn)資源。  

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

5)進(jìn)行線(xiàn)程的清理工作。  

線(xiàn)程完成工作后可能會(huì )自動(dòng)退出,也可能會(huì )阻塞在某處,甚至工作線(xiàn)程還沒(méi)完成工作的時(shí)候主線(xiàn)程已經(jīng)退出,造成整個(gè)進(jìn)程的結束,使程序失敗。有多種方法可以完成線(xiàn)程的清理工作,可以讓主線(xiàn)程調用pthread_join()函數清理工作線(xiàn)程,可以用屏障同步機制清理,也可以用條件變量來(lái)完成清理工作。  

3.2 多線(xiàn)程程序的基本結構  

多線(xiàn)程編程的結構有很多種,但基本的編程結構總結起來(lái)有三種:流水線(xiàn)結構、工作組結構、客戶(hù)端/服務(wù)器結構。這三種結構可以以任意方式組合,來(lái)滿(mǎn)足實(shí)際工程的需求。  

1) 流水線(xiàn)結構  

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




2) 工作組結構  

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


  
圖2 工作組結構  

3) 客戶(hù)端/服務(wù)器結構  

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



4 QNX Neutrino內核對于線(xiàn)程功能的擴展  

具有Neutrino內核的QNX6操作系統對線(xiàn)程的功能進(jìn)行了擴展,提供了一些POSIX標準沒(méi)有提供的功能。  

1)POSIX標準規定使用互斥體的線(xiàn)程必須在同一進(jìn)程內,作為擴展QNX支持在不同進(jìn)程中的線(xiàn)程使用互斥體。如果在兩個(gè)進(jìn)程間創(chuàng )建一塊共享內存,并在內存中初始化一個(gè)互斥體,那么兩個(gè)進(jìn)程之間的線(xiàn)程可以用這個(gè)互斥體來(lái)進(jìn)行同步操作,這是POSIX做不到的。  

2) QNX操作系統還提出了一種獨特的“線(xiàn)程池”概念。當程序需要很多線(xiàn)程同時(shí)工作時(shí),利用“線(xiàn)程池”可以將線(xiàn)程的個(gè)數限定在一定的范圍內!案咚弧、“低水位”的概念分別對應著(zhù)程序中的最大線(xiàn)程數和最小線(xiàn)程數。當程序中線(xiàn)程數目小于“低水位”時(shí),“線(xiàn)程池”會(huì )自動(dòng)創(chuàng )建新的線(xiàn)程進(jìn)行工作,當線(xiàn)程數目大于“高水位”時(shí),“線(xiàn)程池”會(huì )“清除”多于的線(xiàn)程,以防止溢出。這樣程序將始終保持著(zhù)一定數量的線(xiàn)程在工作,“線(xiàn)程池”特別適用客戶(hù)端/服務(wù)器結構,可以很好地保護服務(wù)器的資源。QNX提供了專(zhuān)門(mén)的程序庫來(lái)管理“線(xiàn)程池”頭文件是,相應的API主要有:thread_pool_create(),用于建立一個(gè)線(xiàn)程池,thread_pool_destroy()程序運行結束后用它來(lái)清除線(xiàn)程池,thread_pool_start()用來(lái)啟動(dòng)一個(gè)線(xiàn)程池。  

5 QNX系統下實(shí)用編譯方法  

筆者編制了QNX環(huán)境下的通用Makefile,用于編譯多線(xiàn)程程序,當然也適用于單線(xiàn)程程序的編譯,而這個(gè)Makefile稍加改動(dòng)便可以用于LINUX/UNIX系統中,筆者在RedHat Linux7下試驗通過(guò)。用法,首先將此Makefile 和所要編譯的c/c++程序(支持多個(gè)c/c++程序)/頭文件放置于一個(gè)目錄中,在終端上鍵入make,此Makefile將自動(dòng)把所有相關(guān)源代碼連接編譯成名為go的可執行文件,要運行編譯好的程序,只需在終端上鍵入./go便可。在終端上鍵入make clean將把所有的編譯產(chǎn)生的臨時(shí)文件刪除,只留下原始文件和make文件,在終端上鍵入make depend將檢查文件的依賴(lài)性,源代碼如下:  

EXECUTABLE=go
LINKCC=$(CC)
#如果用于LINUX/UNIX系統,要求安裝可移植線(xiàn)程庫,并裝入下列函數庫
#LIBS=-lm –lpthread -lsocket
#如果用于QNX系統裝入下面的函數庫
LIBS=-lm –lsocket
#如果編譯c++程序將下面gcc改為g++
CC=gcc
CFLAGS=-Wall -g
CXX=g++
CXXFLAGS=$(CFLAGS)
SRCS:=$(wildcard *.c) $(wildcard *.cc) $(wildcard *.C)
OBJS:=$(patsubst %.c,%.o,$(wildcard *.c))\
$(patsubst %.cc,%.o,$(wildcard *.cc))\
$(patsubst %.C,%.o,$(wildcard *.C))
DEPS:=$(patsubst %.o,%.d,$(OBJS))
all:$(EXECUTABLE)
$(EXECUTABLE):$(DEPS) $(OBJS)
$(LINKCC) $(LDFLAGS) -o $(EXECUTABLE) $(OBJS) $(LIBS)
%.d:%.c
$(CC) -M $(CPPFLAGS) $$@
$(CC) -M $(CPPFLAGS) $$@
%.d:%.cc
$(CXX) -M $(CPPFLAGS) $$@
$(CXX) -M $(CPPFLAGS) $$@
%.d:%.C
$(CXX) -M $(CPPFLAGS) $$@
$(CXX) -M $(CPPFLAGS) $$@
clean:
-rm $(OBJS) $(EXECUTABLE) $(DEPS)
# -rm   ./*.* 如果有一些臨時(shí)的記錄文件無(wú)法自動(dòng)去掉加在這里
depend: $(DEPS)
@echo "Dependencies are now up-to-date."  

6 總結  

QNX實(shí)時(shí)操作系統的實(shí)時(shí)性很好,上下文切換時(shí)間、中斷延時(shí)都非常微小,本身提供了對于多線(xiàn)程技術(shù)的強大支持,如果在QNX下使用多線(xiàn)程編程技術(shù)來(lái)解決大型并發(fā)多任務(wù)系統的控制調度,其優(yōu)勢是很大的,前景也是很廣闊的。
本文地址:http://selenalain.com/thread-39726-1-1.html     【打印本頁(yè)】

本站部分文章為轉載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀(guān)點(diǎn)和對其真實(shí)性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問(wèn)題,我們將根據著(zhù)作權人的要求,第一時(shí)間更正或刪除。
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復 返回頂部 返回列表
午夜高清国产拍精品福利|亚洲色精品88色婷婷七月丁香|91久久精品无码一区|99久久国语露脸精品|动漫卡通亚洲综合专区48页