Linux下的多線程機制的分析與實現

來源:互聯網
上載者:User
Linux 下的多線程機制的分析與實現劉井權1   王憲1   周衛雲2(1江南大學通訊與控制工程學院 2無錫梅格科技有限公司 江蘇無錫 214122) 摘要 介紹linux線程的基本概念,線程間的互斥和同步機制,分析了linuxpthread庫的API函數,並結合一個例子闡述多線程編程的核心技術,最後總結出多線程編程應注意的事項。 關鍵詞 線程 進程 同步 互斥中圖分類號:TP316 文獻標識碼:A 1 .引言目前,許多流行的多任務作業系統都提供線程機制,線程就是程式中的單個順序控制流程。利用多線程進行程式設計,就是將一個程式(進程)的任務劃分為執行的多個部分(線程) ,每一個線程為一個順序的單控制流程,而所有線程都是並發執行的,這樣,多線程程式就可以實現並行計算,高效利用多處理器。線程可分為使用者級線程和核心級線程兩種基本類型。 使用者級線程不需要核心支援,可以在使用者程式中實現,線程調度、同步與互斥都需要使用者程式自己完成。 核心級線程需要核心參與,由核心完成線程調度並提供相應的系統調用,使用者程式可以通過這些介面函數對線程進行一定的控制和管理。Linux作業系統提供了LinuxThreads庫,它是符合POSIX1003.1c標準的核心級多線程函數庫。在linuxthreads庫中提供了一些多線程編程的關鍵函數,在多線程編程時應包括pthread.h檔案。 2.LinuxThread 中的關鍵庫函數2.1線程的建立和終止int pthread_create(pthread_t * pthread,const pthread_attr_t *attr,void *(*start_routine(*void)),void *arg);調用此函數可以建立一個新的線程,新線程建立後執行start_routine 指定的程式。其中參數attr是使用者希望建立線程的屬性,當為NULL時表示以預設的屬性建立線程。arg是向start_routine 傳遞的參數。當成功建立一個新的線程時,系統會自動為新線程分配一個線程ID號,並通過pthread 返回給調用者。void pthread_exit(void *value_ptr);調用該函數可以退出線程,參數value_ptr是一個指向返回狀態值的指標。2.2線程式控制制函數pthread_self(void);為了區分線程,線上程建立時系統為其分配一個唯一的ID號,由pthread_create()返回給調用者,也可以通過pthread_self()擷取自己的線程ID。Int pthread_join (pthread- t thread , void * *status);這個函數的作用是等待一個線程的結束。調用pthread_join()的線程將被掛起直到線程ID為參數thread 指定的線程終止。int pthread_detach(pthread_t pthread);參數pthread代表的線程一旦終止,立即釋放調該線程佔有的所有資源。2.3線程間的互斥互斥量和臨界區類似,只有擁有互斥量的線程才具有訪問資源的許可權,由於互斥對象只有一個,這就決定了任何情況下共用資源(代碼或變數)都不會被多個線程同時訪問。使用互斥不僅能夠在同一應用程式的不同線程中實現資源的安全共用,而且可以在不同應用程式的線程之間實現對資源的安全共用。Linux中通過pthread_mutex_t來定義互斥體機制完成互斥操作。具體的操作函數如下pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *attr);初使化一個互斥體變數mutex,參數attr表示按照attr屬性建立互斥體變數mutex,如果參數attr為NULL,則以預設的方式建立。pthread_mutex_lock(pthread_mutex_t *mutex);給一個互斥體變數上鎖,如果mutex指定的互斥體已經被鎖住,則調用線程將被阻塞直到擁有mutex的線程對mutex解鎖為止。Pthread_mutex_unlock(pthread_mutex_t *mutex);對參數mutex指定的互斥體變數解鎖。2.4線程間的同步同步就是線程等待某一個事件的發生,當等待的事件發生時,被等待的線程和事件一起繼續執行。如果等待的事件未到達則掛起。在linux作業系統中是通過條件變數來實現同步的。Pthread_cond_init(pthread_cond_t *cond,const pthread_cond_t *attr);這個函數按參數attr指定的屬性初使化一個條件變數cond。Pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);等待一個事件(條件變數)的發生,發出調用的線程自動阻塞,直到相應的條件變數被置1。等待狀態的線程不佔用CPU時間。pthread_cond_signal(pthread_cond_t *cond);解除一個等待參數cond指定的條件變數的線程的阻塞狀態。 3 .多線程編程的應用執行個體。在這裡利用多線程技術實現生產者和消費者問題,生產者線程向一緩衝區中寫資料,消費者線程從緩衝區中讀取資料,由於生產者線程和消費者線程共用同一緩衝區,為了正確讀寫資料,在使用緩衝隊列時必須保持互斥。生產者線程和消費者線程必須滿足:生產者寫入緩衝區的數目不能超過緩衝區容量,消費者讀取的數目不能超過生產者寫入的數目。在程式中使用了一個小技巧來判斷緩衝區是空還是滿。在初始化時讀指標和寫指標為0;如果讀指標等於寫指標,則緩衝區是空的;如果(寫指標+ 1) % N 等於讀指標,則緩衝區是滿的,%表示取餘數,這時實際上有一個單元空出未用。下面是完整的程式段和注釋。#include<stdio.h>
#include<pthread.h>
#define BUFFER_SIZE 8
struct prodcons {//緩衝區相關資料結構int buffer[BUFFER_SIZE]; //實際資料存放的數組pthread_mutex_t lock;//互斥體lock,用於對緩衝區的互斥操作int readpos , writepos; //讀寫指標pthread_cond_t notempty;//緩衝區非空的條件變數pthread_cond_t notfull; //緩衝區未滿的條件變數};/*初始化緩衝區結構*/void init(struct prodcons * b){pthread_mutex_init(&b->lock,NULL);pthread_cond_init(&b->notempty,NULL);pthread_cond_init(&b->notfull,NULL);b->readpos=0;b->writepos=0;}/*將產品放入緩衝區,這裡是存入一個整數*/void put(struct prodcons* b,int data){pthread_mutex_lock(&b->lock);/*等待緩衝區未滿*/if((b->writepos+1)%BUFFER_SIZE==b->readpos){pthread_cond_wait(&b->notfull,&b->lock) ;}/*寫資料,並移動指標*/b->buffer[b->writepos]=data;b->writepos++;if(b->writepos>= BUFFER_SIZE)b->writepos=0;/*設定緩衝區非空的條件變數*/pthread_cond_signal(&b->notempty);pthread_mutex_unlock(&b->lock);}/*從緩衝區中取出整數*/int get(struct prodcons *b){int data;pthread_mutex_lock(&b->lock);/*等待緩衝區非空*/if(b->writepos==b->readpos){pthread_cond _wait(&b->notempty,&b->lock);}/*讀資料,移動讀指標*/data=b->buffer[b->readpos];b->readpos++;if(b->readpos>=BUFFER_SIZE)b->readpos=0;/*設定緩衝區未滿的條件變數*/Pthread_cond_signal(&b->notfull);Pthread_mutex_unlock(&b->lock);return data;}#define OVER (-1)struct prodcons buffer;void * producer(void *data){int n;for(n=0;n<10000;n++){printf(“%d /n”,n) ;put(&buffer,n);}put(&buffer,OVER);return NULL;}void * consumer(void * data){int d;while(1){d =get(&buffer);if(d==OVER)break;printf(“%d/n”,d) ;}return NULL;}int main(void){pthread_t th_a,th_b;void * retval;init(&buffer);/*建立生產者和消費者線程*/Pthread_create(&th_a,NULL,producer,0);Pthread_create(&th_b,NULL,consumer,0);/*等待兩個線程結束*/Pthread_join(th_a,&retval);Pthread_join(th_b,&retval);return 0;}上面的例子中,生產者負責將1到1000的整數寫入緩衝區,而消費者負責從同一個緩衝區中讀取寫入的整數並列印出來。因為生產者和消費者是兩個同時啟動並執行線程,並且要使用同一個緩衝區進行資料交換,因此必須利用一種機制進行同步。通過上面的例子我們可以看到,多線程的最大好處是,除堆棧之外,幾乎所有的資料均是共用的,因此線程間的通訊效率很高;缺點:因為共用所有資料,從而非常容易導致線程之間互相破壞資料,這一點在編程時必須注意。 4. 結束語Linux中基於POSIX標準的很好的支援了多線程技術,它減少了程式並發執行時的系統開銷,提高了電腦的工作效率。在具體編程過程中要瞭解線程的間的關係,還要考慮共用資料的保護,在互斥和同步機制下保證代碼的高效運行,程式編譯時間用gcc -D –REENTRANT -libpthread.xx.so filename.c編譯。 5. 參考文獻[1]鄭燕飛,餘海燕.Linux的多線程機制探討與實踐[J].電腦應用,2001.[2]劉俞.Linux 多線程的互斥與同步控制及實踐[J].安徽冶金科技職業學院學報,2005.[3]姚繼鋒.Linux 應用執行個體與技巧[M] . 北京:機械工業出版社. 2001[4]魏永明.Linux 實用教程[M]. 北京:電子工業出版社,2000.[5]唐靖飆.UNIX平台下C 語言進階編程指南[M].北京:希望電子出版社,2000.
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.