Linux系統下的多執行緒程式設計入門三

2021-08-25 03:54:15 字數 3198 閱讀 5692

執行緒的資料處理

和程序相比,執行緒的最大優點之一是資料的共享性,各個程序共享父程序處沿襲的資料段,可以方便的獲得、修改資料。但這也給多執行緒程式設計帶來了許多問題。我們必須當心有多個不同的程序訪問相同的變數。許多函式是不可重入的,即同時不能執行乙個函式的多個拷貝(除非使用不同的資料段)。在函式中宣告的靜態變數常常帶來問題,函式的返回值也會有問題。因為如果返回的是函式內部靜態宣告的空間的位址,則在乙個執行緒呼叫該函式得到位址後使用該位址指向的資料時,別的執行緒可能呼叫此函式並修改了這一段資料。在程序中共享的變數必須用關鍵字volatile來定義,這是為了防止編譯器在優化時(如gcc中使用-ox引數)改變它們的使用方式。為了保護變數,我們必須使用訊號量、互斥等方法來保證我們對變數的正確使用。下面,我們就逐步介紹處理執行緒資料時的有關知識。

1、執行緒資料

建立鍵的函式原型為:

extern int pthread_key_create __p ((pthread_key_t *__key,void (*__destr_function) (void *)));

第乙個引數為指向乙個鍵值的指標,第二個引數指明了乙個destructor函式,如果這個引數不為空,那麼當每個執行緒結束時,系統將呼叫這個函式來釋放繫結在這個鍵上的記憶體塊。這個函式常和函式pthread_once ((pthread_once_t*once_control, void (*initroutine) (void)))一起使用,為了讓這個鍵只被建立一次。函式pthread_once宣告乙個初始化函式,第一次呼叫pthread_once時它執行這個函式,以後的呼叫將被它忽略。

在下面的例子中,我們建立乙個鍵,並將它和某個資料相關聯。我們要定義乙個函式 createwindow,這個函式定義乙個圖形視窗(資料型別為fl_window *,這是圖形介面開發工具fltk中的資料型別)。由於各個執行緒都會呼叫這個函式,所以我們使用執行緒資料。

/* 宣告乙個鍵*/

pthread_key_t mywinkey;

/* 函式 createwindow */

void createwindow ( void )

/* 函式 createmykey,建立乙個鍵,並指定了destructor */

void createmykey ( void )

/* 函式 freewinkey,釋放空間*/

void freewinkey ( fl_window * win)

extern int pthread_setspecific __p ((pthread_key_t __key,__const void *__pointer));

extern void *pthread_getspecific __p ((pthread_key_t __key));

這兩個函式的引數意義和使用方法是顯而易見的。要注意的是,用pthread_setspecific為乙個鍵指定新的執行緒資料時,必須自己釋放原有的執行緒資料以**空間。這個過程函式pthread_key_delete用來刪除乙個鍵,這個鍵占用的記憶體將被釋放,但同樣要注意的是,它只釋放鍵占用的記憶體,並不釋放該鍵關聯的執行緒資料所占用的記憶體資源,而且它也不會觸發函式pthread_key_create中定義的destructor函式。執行緒資料的釋放必須在釋放鍵之前完成。

2、互斥鎖

互斥鎖用來保證一段時間內只有乙個執行緒在執行一段**。必要性顯而易見:假設各個執行緒向同乙個檔案順序寫入資料,最後得到的結果一定是災難性的。

我們先看下面一段**。這是乙個讀/寫程式,它們公用乙個緩衝區,並且我們假定乙個緩衝區只能儲存一條資訊。即緩衝區只有兩個狀態:有資訊或沒有資訊。

void reader_function ( void );

void writer_function ( void );

char buffer;

int buffer_has_item=0;

pthread_mutex_t mutex;

struct timespec delay;

void main ( void )

void writer_function (void)

/* 開啟互斥鎖*/

pthread_mutex_unlock(&mutex);

pthread_delay_np(&delay);}}

void reader_function(void)

pthread_mutex_unlock(&mutex);

pthread_delay_np(&delay);}}

這裡宣告了互斥鎖變數mutex,結構pthread_mutex_t為不公開的資料型別,其中包含乙個系統分配的屬性物件。函式 pthread_mutex_init用來生成乙個互斥鎖。null引數表明使用預設屬性。如果需要宣告特定屬性的互斥鎖,須呼叫函式 pthread_mutexattr_init。函式pthread_mutexattr_setpshared和函式 pthread_mutexattr_settype用來設定互斥鎖屬性。前乙個函式設定屬性pshared,它有兩個取值, pthread_process_private和pthread_process_shared。前者用來不同程序中的執行緒同步,後者用於同步本程序的不同執行緒。在上面的例子中,我們使用的是預設屬性pthread_process_ private。後者用來設定互斥鎖型別,可選的型別有pthread_mutex_normal、pthread_mutex_errorcheck、 pthread_mutex_recursive和pthread _mutex_default。它們分別定義了不同的上所、解鎖機制,一般情況下,選用最後乙個預設屬性。

pthread_mutex_lock宣告開始用互斥鎖上鎖,此後的**直至呼叫pthread_mutex_unlock為止,均被上鎖,即同一時間只能被乙個執行緒呼叫執行。當乙個執行緒執行到pthread_mutex_lock處時,如果該鎖此時被另乙個執行緒使用,那此執行緒被阻塞,即程式將等待到另乙個執行緒釋放此互斥鎖。在上面的例子中,我們使用了pthread_delay_np函式,讓執行緒睡眠一段時間,就是為了防止乙個執行緒始終佔據此函式。

上面的例子非常簡單,就不再介紹了,需要提出的是在使用互斥鎖的過程中很有可能會出現死鎖:兩個執行緒試圖同時占用兩個資源,並按不同的次序鎖定相應的互斥鎖,例如兩個執行緒都需要鎖定互斥鎖1和互斥鎖2,a執行緒先鎖定互斥鎖1,b執行緒先鎖定互斥鎖2,這時就出現了死鎖。此時我們可以使用函式 pthread_mutex_trylock,它是函式pthread_mutex_lock的非阻塞版本,當它發現死鎖不可避免時,它會返回相應的資訊,程式設計師可以針對死鎖做出相應的處理。另外不同的互斥鎖型別對死鎖的處理不一樣,但最主要的還是要程式設計師自己在程式設計注意這一點。

Linux系統下C 多執行緒程式設計

2017 0924 c 編譯執行 2017 0924 記錄執行時間 1 c 編譯執行 linux下,c 可執行檔案 out 編譯 c g ex1.cpp o ex1 ex1.cpp 為原始檔,名字字尾名隨意,ex1為可執行性檔案,預設為.out檔案,字尾名省略 c語言 gcc ex1.c o ex1...

linux下多執行緒程式設計

先看執行的結果 1 主函式正在建立執行緒,2執行緒1被建立 3 thread1 i m thread 1th 4執行緒2被建立 5 thread2 i m thread 2nd 6 thread2 number 0 7執行緒3被建立 8主函式正在等待執行緒結束.9 thread1 number 0 ...

Linux下的多執行緒程式設計

執行緒是作業系統能夠進行排程運算的最小單位,它被包含在程序之中,是程序中的實際運作單位。一條執行緒指的是程序中乙個單一順序的控制流,乙個程序可以併發多個執行緒,每條執行緒執行不同的任務。include intpthread create pthread t pthread,const pthread...