天天看點

LINUX總結

LINUX總結

  crazyacking

2016-02-26

主要對socket程式設計,多線程,定時器,條件變量總結

多線程篇

概念:

   多線程就是允許一個程序記憶體存在多個控制權,實作多個線程并發執行。

一個程序中的所有線程共享相同的全局記憶體,還共享程序指令,打開的檔案,描述字,信号處理程式(可以想象成一種線程)和信号設定(signal),目前工作目錄,使用者ID,組ID。

每個線程都有自己的線程ID,寄存器指令,棧,errno,信号掩碼

程序和線程的差別

  fork是昂貴的,記憶體鏡像要把父程序拷貝的子程序,所有描述字要在子程序複制。建立子程序後需要用程序間的通信在父子程序之間拷貝資訊。fork之前的資訊容易傳遞。因為子程序一開始就會有父程序資料空間及所有描述字的拷貝。但是從子程序傳回資訊給父程序需要做更多的工作。

線程是輕權程序。因為線程比程序輕權,建立線程要比程序快10~100倍(N年之前的理論不知道現在如何);

相對程序而言,線程是一個更加接近于執行體的概念,它可以與同程序中的其他線程共享資料,但擁有自己的棧空間,擁有獨立的執行序列。在串行程式基礎上引入線程和程序是為了提高程式的并發度,進而提高程式運作效率和響應時間。

方法簡介

Int pthread_create(pthread_t *tid, pthread_attr_t *attr, void * (*fun), void * arg);

傳回值: 成功為0,出錯時為值Exxx(>0)

*tid  線程ID,如果線程建立成功,其ID将通過tid指針傳回。

*attr 線程的屬性,(優先級,起始棧大小,是否為守護程序),通常使用預設值,在這種情況下我們将attr參數說明為空指針(NULL);

void * (* func)(void *),void* arg);  線程的執行函數,建立成功是将執行此函數。函數的位址由func參數指定,

*arg 是func執行函數的參數 ,是一個指針。 如何我們需要多個調用參數我們必須将它們打包成一個結構,然後将其位址當做唯一的參數傳給其執行函數,

Remark:

與fork()調用建立一個程序的方法不同,pthread_create()建立的線程并不具備與主線程(即調用pthread_create()的線程)同樣的執行序列,而是使其運自己的執行函數。

Pthread函數不設定errno

Pthread_join 

   Int pthread_join(pthread_t tid,void ** status);

    傳回值:成功時為0,出錯時傳回EXXX()0)值

 tid 指定要等待的線程的tid,

 **stauts :  如果stauts 不為NULL,線程的傳回值将被傳遞給status;

該函數:是一個線程阻塞函數;調用它的函數一直等待的線程終止為止,當執行函數傳回時,被等待的線程資源被收回。代碼繼續往下執行

Remark:

疑問:status 可不可以是個結構。當有多個值傳回的時候?

一個線程不能被多個線程等待,否則第一個接收到信号對的線程成功傳回,其餘的調用pthread_join的線程則傳回錯誤代碼ESRCH。

,pthread_join 一個不可 join 的線程(及遊離态), 其傳回結果是不确定的

pthread_t  pthread_self(void)

傳回值:調用線程的線程ID

每個線程都有一個ID以在給定的程序内标示自己。線程ID由pthread_create傳回,線程ID僅僅保證在一個程序内部的唯一性

Int  pthread_detach(pthread_t tid)

作用:将制定線程為脫離的

傳回值:成功傳回0出錯傳回EXXX(>0)值

  線程或者是可彙合的(joinable)(預設值),或者是脫離态(detached)兩種狀态。當可彙合的線程終止時,其線程ID和退出狀态将保留,直到另外一個線程調用pthread_join。脫離的線程像守護程序,當它終止時,素有的資源全部釋放,我們不能等待他終止。如果一個線程需要知道另一個線程什麼時候終止最好保留第二個線程的可彙合性。

如果線程是joinable狀态,當線程函數自己傳回退出時或pthread_exit時都不會釋放線程所占用堆棧和線程描述符(總計8K多)。隻有當你調用了pthread_join之後這些資源才會被釋放。

void Pthread_exit(void *status)

作用:終止線程

傳回值:不傳回調用者。

*status : 程序退出的傳回值。Pthread_join的第二個參數,可以為NULL。

線程退出分為隐式退出,顯示退出

線程退出有三種形式

執行函數執行完(隐式退出)

Return;

Pthread_exit();(顯示退出)

這個函數的功能就是使一個線程正常退出,終止線程,因為我們知道線程它是依賴程序存在的,如果線上程中使用

exit()函數退出,那麼整個的程序将會退出,那麼如果此時你還有一些其它需要做的事情沒有完成呢,這并不是我們所希望的。

。 status:一個傳回值是指針,多個傳回值是結構體

   調用此函數設定status 參數傳回,也可以return傳回。

   Status:不能指向線程内的對象(線程中的變量),因為線程終止時這些對象也消失。

Remark:套接口函數及大多數系統調用出錯時傳回-1,并置errno為正值不通。

互斥鎖的作用,隻有在時間足夠的情況下才能展現出來,即有時線程内需要延時;

互斥鎖

在程式設計中,引入了對象互斥鎖的概念,來保證共享資料操作的完整性。每個對象都對應于一個可稱為" 互斥鎖" 的标記,這個标記用來保證在任一時刻,隻能有一個線程通路該對象。

互斥鎖,是一種信号量,常用來防止兩個程序或線程在同一時刻通路相同的共享資源。可以保證以下三點:

原子性:把一個互斥量鎖定為一個原子操作,這意味着作業系統(或pthread函數庫)保證了如果一個線程鎖定了一個互斥量,沒有其他線程在同一時間可以成功鎖定這個互斥量。

唯一性:如果一個線程鎖定了一個互斥量,在它解除鎖定之前,沒有其他線程可以鎖定這個互斥量。

非繁忙等待:如果一個線程已經鎖定了一個互斥量,第二個線程又試圖去鎖定這個互斥量,則第二個線程将被挂起(不占用任何cpu資源),直到第一個線程解除對這個互斥量的鎖定為止,第二個線程則被喚醒并繼續執行,同時鎖定這個互斥量。

從以上三點,我們看出可以用互斥量來保證對變量(關鍵的代碼段)的排他性通路

常用的5個函數

互斥鎖初始化:pthread_mutex_init

互斥鎖上鎖:pthread_mutex_lock

互斥鎖判斷上鎖:pthread_mutex_trylock

互斥鎖接鎖:pthread_mutex_unlock

消除互斥鎖:pthread_mutex_destroy

Pthread_mutex_t  

  描述: 是個結構體來表示互斥鎖。

Remark: 多個線程 ,同一時間隻能有一個加鎖成功。????

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)

  描述:用*mutexatt來初始化一個互斥鎖mutex.如果mutexattr 為NULL,預設的互斥鎖屬性被使用

  成功傳回 0;失敗傳回Exxx(>0)Exxx為錯誤代碼;

  *mutex: 結構體,

  *mutexattr 互斥鎖的屬性,

* PTHREAD_MUTEX_TIMED_NP,這是預設值,也就是普通鎖。當一個線程加鎖以後,其餘請求鎖的線程将形成一個等待隊列,并在解鎖後按優先級獲得鎖。這種鎖政策保證了資源配置設定的公平性。

* PTHREAD_MUTEX_RECURSIVE_NP,嵌套鎖,允許同一個線程對同一個鎖成功獲得多次,并通過多次unlock解鎖。如果是不同線程請求,則在加鎖線程解鎖時重新競争。

* PTHREAD_MUTEX_ERRORCHECK_NP,檢錯鎖,如果同一個線程請求同一個鎖,則傳回EDEADLK,否則與PTHREAD_MUTEX_TIMED_NP類型動作相同。這樣就保證當不允許多次加鎖時不會出現最簡單情況下的死鎖。

* PTHREAD_MUTEX_ADAPTIVE_NP,适應鎖,動作最簡單的鎖類型,僅等待解鎖後重新競争。

如果互斥鎖類型為 PTHREAD_MUTEX_NORMAL,則不提供死鎖檢測。嘗試重新鎖定互斥鎖會導緻死鎖。如果某個線程嘗試解除鎖定的互斥鎖不是由該線程鎖定或未鎖定,則将産生不确定的行為。

如果互斥鎖類型為 PTHREAD_MUTEX_ERRORCHECK,則會提供錯誤檢查。如果某個線程嘗試重新鎖定的互斥鎖已經由該線程鎖定,則将傳回錯誤。如果某個線程嘗試解除鎖定的互斥鎖不是由該線程鎖定或者未鎖定,則将傳回錯誤。

如果互斥鎖類型為 PTHREAD_MUTEX_RECURSIVE,則該互斥鎖會保留鎖定計數這一概念。線程首次成功擷取互斥鎖時,鎖定計數會設定為 1。線程每重新鎖定該互斥鎖一次,鎖定計數就增加 1。線程每解除鎖定該互斥鎖一次,鎖定計數就減小 1。 鎖定計數達到 0 時,該互斥鎖即可供其他線程擷取。如果某個線程嘗試解除鎖定的互斥鎖不是由該線程鎖定或者未鎖定,則将傳回錯誤。

如果互斥鎖類型是 PTHREAD_MUTEX_DEFAULT,則嘗試以遞歸方式鎖定該互斥鎖将産生不确定的行為。對于不是由調用線程鎖定的互斥鎖,如果嘗試解除對它的鎖定,則會産生不确定的行為。如果嘗試解除鎖定尚未鎖定的互斥鎖,則會産生不确定的行為

初始化互斥鎖有兩種方法

調用pthread_mutex_init();動态初始化。調用pthread_mutex_destroy來銷毀一個互斥鎖;

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER 靜态初始化;

int pthread_mutex_lock(pthread_mutex_t *mutex); 阻塞函數

描述 成功傳回0 錯誤傳回Exxx(>0)設定錯誤,

EAGAIN:由于已超出了互斥鎖遞歸鎖定的最大次數,是以無法擷取該互斥鎖。

EDEADLK:目前線程已經擁有互斥鎖。

*mutex  互斥鎖(已經被初始化)

如果我們試圖為一個已被其他線程鎖住的互斥鎖加鎖,程式便會阻塞直到該互斥鎖被解鎖,

不論那個類型的鎖,都不可能被兩個不同的線程同時得到。而必須等待解鎖。

對于普通鎖和适應鎖類型,解鎖者可以是同程序内任何線程;而檢錯鎖則必須由加鎖者解鎖才有效,否則傳回EPERM;對于嵌套鎖,文檔和實作要求必須由加鎖者解鎖,但實驗結果表明并沒有這種限制,這個不同目前還沒有得到解釋。在同一程序中的線程,如果加鎖後沒有解鎖,則任何其他線程都無法再獲得鎖。加鎖必須解鎖。

nt pthread_mutex_unlock(pthread_mutex_t *mutex);

函數說明::pthread_mutex_unlock() 可釋放 mutex 引用的互斥鎖對象

傳回值:成功完成之後會傳回零

錯誤傳回Exxx(>0)設定錯誤ex:EPERM :目前線程不擁有互斥鎖。

互斥鎖的釋放方式取決于互斥鎖的類型屬性。如果調用 pthread_mutex_unlock() 時有多個線程被 mutex 對象阻塞,則互斥鎖變為可用時排程政策可确定擷取該互斥鎖的線程。

int pthread_mutex_destroy(pthread_mutex_t *mp);

說明:銷毀互斥鎖。

錯誤傳回Exxx(>0)設定錯誤

int pthread_mutex_trylock( pthread_mutex_t *mutex );

說明:嘗試加鎖;

函數是pthread_mutex_lock函數的非阻塞版本。如果mutex參數所指定的互斥鎖已經被鎖定的話,調用pthread_mutex_trylock函數不會阻塞目前線程,而是立即傳回一個值來描述互斥鎖的狀況。

了解了互斥鎖。1.可以一個主線程 激活兩個線程,一個輸出奇數,一個輸出偶數按序輸出。觀察一下有啥情況。奇數線程沒有輸出奇數,而是連續輸出。偶數線程沒有輸出偶數,而是連續輸出。多線程是并發執行,不是并行執行;并行是:某一個瞬時兩個人都在幹活。并發是某一段時間兩個人都在幹活。對于了解多線程很重要

2想讓前面的奇數線程輸出奇數,偶數線程輸出偶數并且按序輸出。這時候都用到條件變量

有時間在總結。

繼續閱讀