第8章 嵌入式Linux多線程編程_第1頁
第8章 嵌入式Linux多線程編程_第2頁
第8章 嵌入式Linux多線程編程_第3頁
第8章 嵌入式Linux多線程編程_第4頁
第8章 嵌入式Linux多線程編程_第5頁
已閱讀5頁,還剩35頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、 第8章 嵌入式Linux多線程編程 目的要求:了解線程的分類。理解多線程處理機(jī)制。掌握Linux線程的概念;多線程編程同步。 重點(diǎn)難點(diǎn):嵌入式Linux多線程程序的實(shí)現(xiàn).進(jìn)程與線程(一) 使用多線程的理由之一是和進(jìn)程相比,它是一種非常節(jié)儉的多任務(wù)操作方式。 在Linux系統(tǒng)下,啟動一個新的進(jìn)程必須分配給它獨(dú)立的地址空間,建立眾多的數(shù)據(jù)表來維護(hù)它的代碼段、堆棧段和數(shù)據(jù)段,這是一種昂貴的多任務(wù)工作方式。 而運(yùn)行于一個進(jìn)程中的多個線程,它們彼此之間使用相同的地址空間,共享大部分?jǐn)?shù)據(jù),啟動一個線程所花費(fèi)的空間遠(yuǎn)遠(yuǎn)小于啟動一個進(jìn)程所花費(fèi)的空間,而且,線程間彼此切換所需的時間也遠(yuǎn)遠(yuǎn)小于進(jìn)程間切換所需要的

2、時間。 進(jìn)程與線程(二)使用多線程的理由之二是線程間方便的通信機(jī)制。 不同的進(jìn)程具有獨(dú)立的數(shù)據(jù)空間,要進(jìn)行數(shù)據(jù)的傳遞只能通過通信的方式進(jìn)行 同一進(jìn)程下的線程之間共享數(shù)據(jù)空間,所以一個線程的數(shù)據(jù)可以直接為其它線程所用 多線程程序的優(yōu)點(diǎn)提高應(yīng)用程序響應(yīng)。當(dāng)一個操作耗時很長時,整個系統(tǒng)都會等待這個操作,多線程技術(shù)會將耗時長的操作(time consuming)置于一個新的線程。使多CPU系統(tǒng)更加有效。操作系統(tǒng)會保證當(dāng)線程數(shù)不大于CPU數(shù)目時,不同的線程運(yùn)行于不同的CPU上。改善程序結(jié)構(gòu)。一個既長又復(fù)雜的進(jìn)程可以考慮分為多個線程,成為幾個獨(dú)立或半獨(dú)立的運(yùn)行部分。多線程編程起步編寫Linux下的多線程程

3、序,需要使用頭文件pthread.h ,連接時需要使用庫libpthread.a 多線程程序?qū)嵗?/* example.c*/#include #include void thread(void)int i;for(i=0;i3;i+)printf(This is a pthread.n); int main(void)pthread_t id;int i,ret;ret=pthread_create(&id,NULL,(void *) thread,NULL);if(ret!=0)printf (Create pthread error!n);exit (1); for(i=0;i3;i+)

4、printf(This is the main process.n);pthread_join(id,NULL);return (0);執(zhí)行:gcc example.c -lpthread -o example -l參數(shù)用于指定編譯時要用到的庫運(yùn)行生成的example每次運(yùn)行的結(jié)果可能不同,這是因?yàn)閮蓚€線程在爭奪CPU資源線程標(biāo)識符 pthread_t pthread_t在頭文件/usr/include/bits/pthreadtypes.h中定義:typedef unsigned long int pthread_t;用來標(biāo)識一個線程主要API函數(shù)介紹LIBC中的pthread庫提供了大量的

5、API函數(shù)在PC機(jī)的Linux系統(tǒng)中,其庫文件的路徑一般是/usr/lib$cd /usr/lib$ls libpthread.*/usr/lib/libpthread.a /usr/lib/libpthread.solibpthread.a 和libpthread.so分別是pthread庫的靜態(tài)和動態(tài)鏈接庫文件線程創(chuàng)建函數(shù)pthread_create 函數(shù)原型:int pthread_create (pthread_t * thread_id, _const pthread_attr_t * _attr, void *(*_start_routine) (void *),void *_re

6、strict _arg) 第一個參數(shù)為指向線程標(biāo)識符的指針 第二個參數(shù)用來設(shè)置線程屬性 第三個參數(shù)是線程運(yùn)行函數(shù)的起始地址 最后一個參數(shù)是運(yùn)行函數(shù)的參數(shù) 函數(shù)thread不需要參數(shù),所以最后一個參數(shù)設(shè)為空指針。第二個參數(shù)也設(shè)為空指針,這樣將生成默認(rèn)屬性的線程。 當(dāng)創(chuàng)建線程成功時,函數(shù)返回0,若不為0則說明創(chuàng)建線程失敗,常見的錯誤返回代碼為EAGAIN和EINVAL。前者表示系統(tǒng)限制創(chuàng)建新的線程,例如線程數(shù)目過多了;后者表示第二個參數(shù)代表的線程屬性值非法。 創(chuàng)建線程成功后,新創(chuàng)建的線程則運(yùn)行參數(shù)三和參數(shù)四確定的函數(shù),原來的線程則繼續(xù)運(yùn)行下一行代碼。pthread_join函數(shù) 用來等待一個線程的

7、結(jié)束。 函數(shù)原型:int pthread_join (pthread_t _th, void *_thread_return)第一個參數(shù)為被等待的線程標(biāo)識符 。第二個參數(shù)為一個用戶定義的指針,用來存儲被等待線程返回值。 這個函數(shù)是一個線程阻塞的函數(shù),調(diào)用它的函數(shù)將一直等待到被等待的線程結(jié)束為止,當(dāng)函數(shù)返回時,被等待線程的資源被收回。 pthread_exit函數(shù)一個線程的結(jié)束有兩種途徑,一種是象我們上面的例子,函數(shù)結(jié)束了,調(diào)用它的線程也就結(jié)束了;另一種方式是通過函數(shù)pthread_exit實(shí)現(xiàn) 。 函數(shù)原型:void pthread_exit (void *_retval)唯一的參數(shù)是函數(shù)的返

8、回代碼 。如果pthread_join中的第二個參數(shù)thread_return不是NULL,這個值將被傳遞給 thread_return。 需要注意的是:一個線程不能被多個線程等待,否則第一個接收到信號的線程成功返回,其余調(diào)用pthread_join的線程則返回錯誤代碼ESRCH。 線程的屬性線程的屬性 使用pthread_create函數(shù)創(chuàng)建線程時,線程參數(shù)一般都為默認(rèn)值,即將第二個參數(shù)設(shè)為NULL ,對大多數(shù)程序來說,使用默認(rèn)屬性就夠了屬性結(jié)構(gòu)為pthread_attr_t,它在頭文件/usr/include/pthread.h中定義,屬性值不能直接設(shè)置,須使用相關(guān)函數(shù)進(jìn)行操作,初始化的函

9、數(shù)為pthread_attr_init,這個函數(shù)必須在pthread_create函數(shù)之前調(diào)用。 線程的優(yōu)先級 線程的優(yōu)先級是線程的常用屬性, 它存放在結(jié)構(gòu)sched_param中。用函數(shù)pthread_attr_getschedparam和函數(shù) pthread_attr_setschedparam進(jìn)行存放,一般是先取優(yōu)先級,對取得的值修改后再存放回去。下面是一個簡單的例子: #include #include pthread_attr_t attr;pthread_t tid;sched_param param;int newprio=20; pthread_attr_init(&attr)

10、;pthread_attr_getschedparam(&attr, ¶m);param.sched_priority=newprio;pthread_attr_setschedparam(&attr, ¶m);pthread_create(&tid, &attr, (void *)myfunction, myarg);互斥鎖 互斥鎖用來保證一段時間內(nèi)只有一個線程在執(zhí)行一段代碼 看下面一段代碼。這是一個讀/寫程序,它們公用一個緩沖區(qū),并且假定一個緩沖區(qū)只能保存一條信息。即緩沖區(qū)只有兩個狀態(tài):有信息或沒有信息。void reader_function ( void );void

11、writer_function ( void ); char buffer;int buffer_has_item=0;pthread_mutex_t mutex;struct timespec delay;void main ( void )pthread_t reader;/* 定義延遲時間*/delay.tv_sec = 2;delay.tv_nec = 0;/* 用默認(rèn)屬性初始化一個互斥鎖對象*/pthread_mutex_init (&mutex,NULL);pthread_create(&reader, pthread_attr_default, (void *)&reader_f

12、unction), NULL);writer_function( ); void writer_function (void)while(1)/* 鎖定互斥鎖*/pthread_mutex_lock (&mutex);if (buffer_has_item=0)buffer=make_new_item( );buffer_has_item=1;/* 打開互斥鎖*/pthread_mutex_unlock(&mutex);pthread_delay_np(&delay); void reader_function(void)while(1)pthread_mutex_lock(&mutex);i

13、f(buffer_has_item=1)consume_item(buffer);buffer_has_item=0;pthread_mutex_unlock(&mutex);pthread_delay_np(&delay);聲明互斥鎖變量pthread_mutex_t mutex函數(shù) pthread_mutex_init用來生成一個互斥鎖。NULL參數(shù)表明使用默認(rèn)屬性。 pthread_mutex_lock聲明開始用互斥鎖上鎖,此后的代碼直至調(diào)用pthread_mutex_unlock為止,均被上鎖,即同一時間只能被一個線程調(diào)用執(zhí)行。當(dāng)一個線程執(zhí)行到pthread_mutex_lock處時,

14、如果該鎖此時被另一個線程使用,那此線程被阻塞,即程序?qū)⒌却搅硪粋€線程釋放此互斥鎖。在上面的例子中,我們使用了pthread_delay_np函數(shù),讓線程睡眠一段時間,就是為了防止一個線程始終占據(jù)此函數(shù)。 條件變量條件變量 使用互斥鎖可實(shí)現(xiàn)線程間數(shù)據(jù)的共享和通信,互斥鎖一個明顯的缺點(diǎn)是它只有兩種狀態(tài):鎖定和非鎖定。而條件變量通過允許線程阻塞和等待另一個線程發(fā)送信號的方法彌補(bǔ)了互斥鎖的不足,它常和互斥鎖一起使用。使用時,條件變量被用來阻塞一個線程,當(dāng)條件不滿足時,線程往往解開相應(yīng)的互斥鎖并等待條件發(fā)生變化。一旦其它的某個線程改變了條件變量,相應(yīng)的條件變量喚醒一個或多個正被此條件變量阻塞的線程。這

15、些線程將重新鎖定互斥鎖并重新測試條件是否滿足。 pthread_cond_init函數(shù) 條件變量的結(jié)構(gòu)為pthread_cond_t,函數(shù)pthread_cond_init()被用來初始化一個條件變量。它的原型為:int pthread_cond_init (pthread_cond_t * cond, _const pthread_condattr_t * cond_attr)其中cond是一個指向結(jié)構(gòu)pthread_cond_t的指針cond_attr是一個指向結(jié)構(gòu)pthread_condattr_t的指針。結(jié)構(gòu)pthread_condattr_t是條件變量的屬性結(jié)構(gòu) 注意:條件變量只有在

16、未被使用時才能重新初始化或被釋放。釋放一個條件變量的函數(shù)為pthread_cond_ destroy(pthread_cond_t cond)。pthread_cond_wait函數(shù) 使線程阻塞在一個條件變量上。 函數(shù)原型:extern int pthread_cond_wait (pthread_cond_t *_restrict_cond, pthread_mutex_t *_restrict _mutex) 線程解開mutex指向的鎖并被條件變量cond阻塞。線程可以被函數(shù)pthread_cond_signal和函數(shù)pthread_cond_broadcast喚醒 但是要注意的是,條件變

17、量只是起阻塞和喚醒線程的作用,具體的判斷條件還需用戶給出,例如一個變量是否為0等等, 線程被喚醒后,它將重新檢查判斷條件是否滿足,如果還不滿足,一般說來線程應(yīng)該仍阻塞在這里,等待被下一次喚醒。這個過程一般用while語句實(shí)現(xiàn)。 pthread_cond_timedwait函數(shù) 也可以用來阻塞線程函數(shù)原型:extern int pthread_cond_timedwait (pthread_cond_t *_cond, pthread_mutex_t *_mutex, _const struct timespec *_abstime)它比函數(shù)pthread_cond_wait()多了一個時間參數(shù)

18、,經(jīng)歷abstime段時間后,即使條件變量不滿足,阻塞也被解除。pthread_cond_signal函數(shù) 用來釋放被阻塞在條件變量cond上的一個線程。 函數(shù)原型:extern int pthread_cond_signal (pthread_cond_t *_cond)多個線程阻塞在此條件變量上時,哪一個線程被喚醒是由線程的調(diào)度策略所決定的。 使用函數(shù)pthread_cond_wait()和函數(shù)pthread_cond_signal()的一個簡單的例子 pthread_mutex_t count_lock;pthread_cond_t count_nonzero;unsigned coun

19、t;decrement_count() pthread_mutex_lock (&count_lock);while(count=0) pthread_cond_wait( &count_nonzero, &count_lock);count=count -1;pthread_mutex_unlock (&count_lock);increment_count()pthread_mutex_lock(&count_lock);if(count=0)pthread_cond_signal(&count_nonzero);count=count+1;pthread_mutex_unlock(&co

20、unt_lock);count值為0時, decrement函數(shù)pthread_cond_wait處被阻塞,并打開互斥鎖count_lock。此時,當(dāng)調(diào)用到函數(shù) increment_count時,pthread_cond_signal()函數(shù)改變條件變量,告知decrement_count()停止阻塞。 下面我們分析一下著名的生產(chǎn)者消費(fèi)者問題模型的實(shí)現(xiàn)主程序中分別啟動生產(chǎn)者線程和消費(fèi)者線程。生產(chǎn)者線程不斷順序地將0到1000的數(shù)字寫入共享的循環(huán)緩沖區(qū),同時消費(fèi)者線程不斷地從共享的循環(huán)緩沖區(qū)讀取數(shù)據(jù)。 生產(chǎn)者寫入緩沖區(qū)和消費(fèi)者從緩沖區(qū)讀數(shù)的具體流程: 生產(chǎn)者首先要獲得互斥鎖,并且判斷寫指針+1后

21、是否等于讀指針,如果相等則進(jìn)入等待狀態(tài),等候條件變notfull;如果不等則向緩沖區(qū)中寫一個整數(shù),并且設(shè)置條件變量為notempty,最后釋放互斥鎖。消費(fèi)者線程與生產(chǎn)者線程類似 。生產(chǎn)者寫入共享的循環(huán)緩沖區(qū)函數(shù)生產(chǎn)者寫入共享的循環(huán)緩沖區(qū)函數(shù)PUTvoid put(struct prodcons * b, int data)pthread_mutex_lock(&b-lock); /獲取互斥鎖while (b-writepos + 1) % BUFFER_SIZE = b-readpos) /如果讀寫位置相同pthread_cond_wait(&b-notfull, &b-lock);/等待狀態(tài)變量b-notfull,不滿則跳出阻塞。b-buff

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論