日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Linux多線程編程指南:提高程序性能的有效手段(在linux中運用多線程知識)

隨著計算機技術(shù)的飛速發(fā)展,人們對計算機性能的要求也越來越高。為了提高程序的執(zhí)行效率,多線程編程成為了一個不可或缺的手段。而作為高效、穩(wěn)定性極佳的操作系統(tǒng)之一,Linux自然也成為了多線程編程的首選平臺。

十年的郫都網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。成都營銷網(wǎng)站建設(shè)的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整郫都建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)建站從事“郫都網(wǎng)站設(shè)計”,“郫都網(wǎng)站推廣”以來,每個客戶項目都認真落實執(zhí)行。

本文將介紹Linux多線程編程的基本思想、相關(guān)概念及實例,幫助讀者掌握Linux多線程編程的核心技巧,提高程序性能,實現(xiàn)更為高效的計算機應(yīng)用程序。

一、多線程編程的基本思想

多線程編程的基本思想是利用多線程來解決單線程執(zhí)行效率低下的問題。多線程程序在執(zhí)行時會分配多個線程來同時執(zhí)行不同的任務(wù),從而加速整個程序的執(zhí)行速度。

多線程編程的核心思想是并發(fā)執(zhí)行。在單線程程序中,代碼是按照一定的順序執(zhí)行的,需要等到當前任務(wù)完成之后,才能進行下一個任務(wù)。而在多線程程序中,每個線程可以并發(fā)執(zhí)行一個任務(wù),不需要等待其他線程完成,從而更大化地利用了處理器的并行性能。

在 Linux 中,多線程編程程序是采用線程庫來實現(xiàn)的。線程是相對輕量級的執(zhí)行單元,線程的創(chuàng)建、管理和銷毀都是由操作系統(tǒng)負責的,使開發(fā)人員能夠針對問題的性質(zhì)選擇合適的并發(fā)模型,通過線程庫對線程進行管理和調(diào)度,實現(xiàn)高效的程序執(zhí)行。

二、多線程編程的相關(guān)概念

1.線程和進程

在 Linux 中,一個進程可以包含多個線程。進程是操作系統(tǒng)中任務(wù)的基本單位,而線程則是進程中的執(zhí)行單元。每個線程擁有自己的棧、程序計數(shù)器和寄存器,以及可自行調(diào)度的優(yōu)先級等信息,但不擁有獨立的代碼、數(shù)據(jù)和堆??臻g。

多線程程序中,通常會同時創(chuàng)建多個線程,每個線程都可以獨立進行執(zhí)行不同的任務(wù)。線程之間可以共享進程的資源,如內(nèi)存空間、文件描述符等,但也需要考慮線程競爭和同步問題。

2.線程同步和互斥

在線程中,如果多個線程同時訪問同一塊資源(如內(nèi)存),就可能會發(fā)生不可預期的情況,如數(shù)據(jù)混雜、死鎖等。因此,在多線程編程中必須采用互斥和同步技術(shù)(如信號量、互斥鎖、條件變量等)來解決線程之間的競爭問題,保證線程執(zhí)行的正確性。

互斥是一種保證臨界區(qū)內(nèi)代碼不被多個線程同時執(zhí)行的方法。在臨界區(qū)的代碼中,需要加入互斥鎖進行保護,當一個線程進入臨界區(qū)時,會鎖定互斥鎖,其他線程則不能進入臨界區(qū),直到當前線程解鎖互斥鎖,其他線程才能繼續(xù)執(zhí)行臨界區(qū)的代碼。

同步則是通過信號量、條件變量等來實現(xiàn)線程之間的協(xié)作。例如,生產(chǎn)者線程和消費者線程之間,需要通過信號量來協(xié)調(diào)生產(chǎn)和消費的數(shù)量和時間,避免隊列溢出和資源浪費等問題。

三、多線程編程的實例

下面通過代碼示例來說明Linux下多線程編程的實現(xiàn)過程。

1、創(chuàng)建線程

在 Linux 中,線程的創(chuàng)建可以采用 pthread_create() 函數(shù)實現(xiàn)。函數(shù)原型如下:

#include

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

其中,參數(shù)說明如下:

thread:指向 pthread_t 類型數(shù)據(jù)的指針,用于存儲創(chuàng)建后線程的 ID;

attr:線程屬性,通常為 NULL;

start_routine:指向線程主函數(shù)的指針;

arg:向線程主函數(shù)傳遞的參數(shù)。

2、線程同步和互斥

在多線程編程中,需要考慮線程的同步和互斥,以保證程序的正確性和穩(wěn)定性。例如,下面實現(xiàn)了一個線程安全的隊列:

typedef struct {

void **items;

int max_size;

int front;

int rear;

pthread_mutex_t lock;

pthread_cond_t has_items;

pthread_cond_t has_space;

} SafeQueue;

void safe_queue_init(SafeQueue *queue, int max_items) {

queue->items = malloc(sizeof(void*) * max_items);

queue->max_size = max_items;

queue->front = 0;

queue->rear = 0;

pthread_mutex_init(&queue->lock, NULL);

pthread_cond_init(&queue->has_items, NULL);

pthread_cond_init(&queue->has_space, NULL);

}

void safe_queue_push(SafeQueue *queue, void *item) {

pthread_mutex_lock(&queue->lock);

while(queue->rear >= queue->max_size) {

pthread_cond_wt(&queue->has_space, &queue->lock);

}

queue->items[queue->rear] = item;

queue->rear++;

pthread_cond_signal(&queue->has_items);

pthread_mutex_unlock(&queue->lock);

}

void *safe_queue_pop(SafeQueue *queue) {

pthread_mutex_lock(&queue->lock);

while(queue->front == queue->rear) {

pthread_cond_wt(&queue->has_items, &queue->lock);

}

void *item = queue->items[queue->front];

queue->front++;

pthread_cond_signal(&queue->has_space);

pthread_mutex_unlock(&queue->lock);

return item;

}

在上述代碼中,通過互斥鎖 pthread_mutex_lock() 和信號量 pthread_cond_wt() 來保證線程的安全同步,滿足生產(chǎn)者和消費者之間的交替需求;同時,還使用了條件變量 pthread_cond_signal() 來及時通知對應(yīng)線程,避免線程出現(xiàn)阻塞等待的情況。

3、線程池

在多線程編程中,線程池是一種非常重要的技術(shù),可以有效地控制線程的資源使用,并提高程序的效率。下面實現(xiàn)了一個線程池的例子:

typedef struct {

SafeQueue task_queue;

pthread_t *threads;

int num_threads;

int shutdown;

} ThreadPool;

void thread_pool_init(ThreadPool *pool, int num_threads) {

pool->threads = malloc(sizeof(pthread_t) * num_threads);

pool->num_threads = num_threads;

pool->shutdown = 0;

safe_queue_init(&pool->task_queue, num_threads);

for(int i = 0; i

pthread_create(&pool->threads[i], NULL, thread_pool_worker, pool);

}

}

void thread_pool_add_task(ThreadPool *pool, void (*task)(void *), void *arg) {

Task *t = malloc(sizeof(Task));

t->task_fn = task;

t->arg = arg;

safe_queue_push(&pool->task_queue, t);

}

void thread_pool_shutdown(ThreadPool *pool) {

for(int i = 0; i num_threads; i++) {

pthread_join(pool->threads[i], NULL);

}

pool->shutdown = 1;

}

void *thread_pool_worker(void *arg) {

ThreadPool *pool = (ThreadPool*) arg;

while(!pool->shutdown) {

Task *t = safe_queue_pop(&pool->task_queue);

if(t != NULL) {

t->task_fn(t->arg);

free(t);

}

}

return NULL;

}

在上述代碼中,我們首先通過 SafeQueue 實現(xiàn)了一個線程安全的任務(wù)隊列,然后通過線程池實現(xiàn)了任務(wù)的分發(fā)和管理。線程池包含了多個線程,每個線程都會不斷地從隊列中獲取任務(wù)進行處理,每個任務(wù)都將被一個獨立的線程執(zhí)行,從而有效地發(fā)揮了計算機的并行性能。

成都網(wǎng)站建設(shè)公司-創(chuàng)新互聯(lián)為您提供網(wǎng)站建設(shè)、網(wǎng)站制作、網(wǎng)頁設(shè)計及定制高端網(wǎng)站建設(shè)服務(wù)!

linux 多線程環(huán)境下的幾種鎖機制

NO1

互斥量(Mutex)

互斥量是實現(xiàn)最簡單的鎖類型,因此有一些教科書一般以互斥量為例對鎖原語進行描述?;コ饬康尼尫挪⒉粌H僅依賴于釋放操作,還可以引入一個定時器屬性。如果在釋放操作執(zhí)行前發(fā)生定時器超時,則互斥量也會釋放代碼塊或共享存儲區(qū)供其他線程訪問。當有異常發(fā)生時,可使用try-finally語句來確?;コ饬勘会尫?。定時器狀態(tài)或try-finally語句的使用可以避免產(chǎn)生死鎖。

遞歸鎖(Recursive

Lock)

遞歸鎖是指可以被當前持有該鎖的線程重復獲取,而不會導致該線程產(chǎn)生死鎖的鎖類型。對遞歸鎖而言,只有在當前持有線程的獲取鎖操作都有一個釋放操作與之對應(yīng)時,其他線程才可以獲取該鎖。因此,在使用遞歸鎖時,必須要用足夠的釋放鎖操作來平衡獲取鎖操作,實現(xiàn)這一目標的更佳方式是在單入口單出口代碼塊的兩頭一一對應(yīng)地使用獲取、釋放操作,做法和在普通鎖中一樣。遞歸鎖在遞歸函數(shù)中最有用。但是,總的來說,遞歸鎖比非遞歸鎖速度要慢。需要注意的是:調(diào)用線程獲得幾次遞歸鎖必須釋放幾次遞歸鎖。

以下為一個遞歸鎖的示例:

view plain copy

Recursive_Lock L

void recursiveFunction (int count) {

L->acquire()

if (count > 0) {

count = count – 1;

recursiveFunction(count);

}

L->release();

}

讀寫鎖(Read-Write

lock) 讀寫鎖又稱為共享獨占鎖(shared-exclusive

lock)、多讀單寫鎖(multiple-read/single-write lock)或者非互斥信號量(non-mutual

exclusion

semaphore)。讀寫鎖允許多個線程同時進行讀訪問,但是在某一時刻卻最多只能由一個線程執(zhí)行寫操作。對于多個線程需要同時讀共享數(shù)據(jù)卻并不一定進行寫操作的應(yīng)用來說,讀寫鎖是一種高效的同步機制。對于較長的共享數(shù)據(jù),只為其設(shè)置一個讀寫鎖會導致較長的訪問時間,更好將其劃分為多個小段并設(shè)置多個讀寫鎖以進行同步。

這個讀寫鎖我們在學習數(shù)據(jù)庫的時候應(yīng)該很熟悉的喲!

旋轉(zhuǎn)鎖(Spin

Lock)

旋轉(zhuǎn)鎖是一種非阻塞鎖,由某個線程獨占。采用旋轉(zhuǎn)鎖時,等待線程并不靜態(tài)地阻塞在同步點,而是必須“旋轉(zhuǎn)”,不斷嘗試直到最終獲得該鎖。旋轉(zhuǎn)鎖多用于多處理器系統(tǒng)中。這是因為,如果在單核處理器中采用旋轉(zhuǎn)鎖,當一個線程正在“旋轉(zhuǎn)”時,將沒有執(zhí)行資源可供另一釋放鎖的線程使用。旋轉(zhuǎn)鎖適合于任何鎖持有時間少于將一個線程阻塞和喚醒所需時間的場合。線程控制的變更,包括線程上下文的切換和線程數(shù)據(jù)結(jié)構(gòu)的更新,可能比旋轉(zhuǎn)鎖需要更多的指令周期。旋轉(zhuǎn)鎖的持有時間應(yīng)該限制在線程上下文切換時間的50%到100%之間(Kleiman,1996年)。在線程調(diào)用其他子系統(tǒng)時,線程不應(yīng)持有旋轉(zhuǎn)鎖。對旋轉(zhuǎn)鎖的不當使用可能會導致線程餓死,因此需謹慎使用這種鎖機制。旋轉(zhuǎn)鎖導致的餓死問題可使用排隊技術(shù)來解決,即每個等待線程按照先進先出的順序或者隊列結(jié)構(gòu)在一個獨立的局部標識上進行旋轉(zhuǎn)。

淺談linux 多線程編程和 windows 多線程編程的異同

很早以前就想寫寫linux下多線程編程和windows下的多線程編程了,但是每當寫時又不知道從哪個地方寫起,怎樣把自己知道的東西都寫出來,下面我就談世罩讓談linux多線程及線程同步,并將它和windows的多線程進行比較,看看他們之間有什么相同點和不同的地方。

其實最開始我是搞windows下編程的,包括windows編程,windows 驅(qū)動,包括u驅(qū)動,ndis驅(qū)動,pci驅(qū)動,1394驅(qū)動等等,同時也一條龍服務(wù),做windows下的應(yīng)用程序開發(fā),后面慢慢的我又對linux開發(fā)產(chǎn)生比較深的興趣和愛好,就轉(zhuǎn)到搞linux開發(fā)了。在接下來的我還會寫一些博客,主要是寫linux編程和windows編程的區(qū)別吧,現(xiàn)在想寫的是linux下u驅(qū)動和windows下u驅(qū)動開發(fā)的區(qū)別,這些都是后話,等我將linux多線程和windows多線程講解完后,我再寫一篇u驅(qū)動,談?wù)剋indows 和linux u驅(qū)動的東東。好了,言歸正傳。開始將多線程了。

首先我們講講為什么搜局要采用多線程編程,其實并不是所有的程序都必須采用多線程,有些時候采用多線程,性能還沒有單線程好。所以我們要搞清楚,什么時候采用多線程。采用多線程的好處如下:

(1)因為多線程彼此之間采用相同的地址空間,共享大部分的數(shù)據(jù),這樣和多進程相比,代價比較節(jié)儉,因為多進程的話,啟動新的進程必須分配給它獨立的地址空間,這樣需要數(shù)據(jù)表來維護代碼段,數(shù)據(jù)段和堆棧段等等。

(2)多線程和多進程相比,一個明顯的優(yōu)點就是線程之間的通信了,對不同進程來說,它們具有獨立的數(shù)據(jù)空間,要進行數(shù)據(jù)的傳遞只能通過通信的方式進行,這種方式不僅費時,而且很不方便。但是對于多線程就不一樣了。他們之間可以直接共享數(shù)據(jù),比如最簡單的方式就是共享全局變量。但是共享全部變量也要注意哦,呵呵,必須注意同步,不然后果你知道的。呵呵。

(3)在多cpu的情況下,不同的線程可以運行不同的cpu下,這樣就完全并行了。

反正我覺得在這種情況下,采用多線程比較理想。比如說你要做一個任務(wù)分2個步驟,你為提高工作效率,你可以多線程技術(shù),開辟2個線程,之一個線程就做之一步的工作,第2個線程就做第2步的工作。但是你這個時候要注意同步了。因為只有之一步做完才能做第2步的工作。這時,我們可以采用同步技術(shù)進行線程之間的通信。

針對這種情況,我們首先講講多線程之間的通信,在windows平臺下,多線程之間通信采用的方法主要有:

(1)共享全局變量,這種悶仔方法是最容易想到的,呵呵,那就首先講講吧,比如說吧,上面的問題,之一步要向第2步傳遞收據(jù),我們可以之間共享全局變量,讓兩個線程之間傳遞數(shù)據(jù),這時主要考慮的就是同步了,因為你后面的線程在對數(shù)據(jù)進行操作的時候,你之一個線程又改變了數(shù)據(jù)的內(nèi)容,你不同步保護,后果很嚴重的。你也知道,這種情況就是讀臟數(shù)據(jù)了。在這種情況下,我們最容易想到的同步方法就是設(shè)置一個bool flag了,比如說在第2個線程還沒有用完數(shù)據(jù)前,之一個線程不能寫入。有時在2個線程所需的時間不相同的時候,怎樣達到更大效率的同步,就比較麻煩了。咱們可以多開幾個緩沖區(qū)進行操作。就像生產(chǎn)者消費者一樣了。如果是2個線程一直在跑的,由于時間不一致,緩沖區(qū)遲早會溢出的。在這種情況下就要考慮了,是不讓數(shù)據(jù)寫入還是讓數(shù)據(jù)覆蓋掉老的數(shù)據(jù),這時候就要具體問題具體分析了。就此打住,呵呵。就是用bool變量控制同步,linux 和windows是一樣的。

既然講道了這里,就再講講其它同步的方法。同樣 針對上面的這個問題,共享全局變量同步問題。除了采用bool變量外,最容易想到的方法就是互斥量了。呵呵,也就是傳說中的加鎖了。windows下加鎖和linux下加鎖是類似的。采用互斥量進行同步,要想進入那段代碼,就先必須獲得互斥量。

linux上互斥量的函數(shù)是:

windows下互斥量的函數(shù)有:createmutex 創(chuàng)建一個互斥量,然后就是獲得互斥量waitforsingleobject函數(shù),用完了就釋放互斥量ReleaseMutex(hMutex),當減到0的時候 內(nèi)核會才會釋放其對象。下面是windows下與互斥的幾個函數(shù)原型。

HANDLE WINAPI CreateMutex(

__in LPSECURITY_ATTRIBUTES lpMutexAttributes,

__in BOOL bInitialOwner,

__in LPCTSTR lpName

);

可以可用來創(chuàng)建一個有名或無名的互斥量對象

之一參數(shù) 可以指向一個結(jié)構(gòu)體SECURITY_ATTRIBUTES 一般可以設(shè)為null;

第二參數(shù) 指當時的函數(shù)是不是感應(yīng)感應(yīng)狀態(tài) FALSE為當前擁有者不會創(chuàng)建互斥

第三參數(shù) 指明是否是有名的互斥對象 如果是無名 用null就好。

DWORD WINAPI WaitForSingleObject(

__in HANDLE hHandle,

__in DWORD dwMilliseconds

);

之一個是 創(chuàng)建的互斥對象的句柄。第二個是 表示將在多少時間之后返回 如果設(shè)為宏INFINITE 則不會返回 直到用戶自己定義返回。

對于linux操作系統(tǒng),互斥也是類似的,只是函數(shù)不同罷了。在linux下,和互斥相關(guān)的幾個函數(shù)也要閃亮登場了。

pthread_mutex_init函數(shù):初始化一個互斥鎖;

pthread_mutex_destroy函數(shù):注銷一個互斥鎖;

pthread_mutex_lock函數(shù):加鎖,如果不成功,阻塞等待;

pthread_mutex_unlock函數(shù):解鎖;

pthread_mutex_trylock函數(shù):測試加鎖,如果不成功就立即返回,錯誤碼為EBUSY;

至于這些函數(shù)的用法,google上一搜,就出來了,呵呵,在這里不多講了。windows下還有一個可以用來保護數(shù)據(jù)的方法,也是線程同步的方式

就是臨界區(qū)了。臨界區(qū)和互斥類似。它們之間的區(qū)別是,臨界區(qū)速度快,但是它只能用來同步同一個進程內(nèi)的多個線程。臨界區(qū)的獲取和釋放函數(shù)如下:

EnterCriticalSection() 進入臨界區(qū); LeaveCriticalSection()離開臨界區(qū)。 對于多線程共享內(nèi)存的東東就講到這里了。

(2)采用消息機制進行多線程通信和同步,windows下面的的消息機制的函數(shù)用的多的就是postmessage了。Linux下的消息機制,我用的較少,就不在這里說了,如果誰熟悉的,也告訴我,呵呵。

(3)windows下的另外一種線程通信方法就是事件和信號量了。同樣針對我開始舉得例子,2個線程同步,他們之間傳遞信息,可以采用事件(Event)或信號量(Semaphore),比如之一個線程完成生產(chǎn)的數(shù)據(jù)后,就必須告訴第2個線程,他已經(jīng)把數(shù)據(jù)準備好了,你可以來取走了。第2個線程就把數(shù)據(jù)取走。呵呵,這里可以采用消息機制,當之一個線程準備好數(shù)據(jù)后,就直接postmessage給第2個線程,按理說采用postmessage一個線程就可以搞定這個問題了。呵呵,不是重點,省略不講了。

對于linux,也有類似的方法,就是條件變量了,呵呵,這里windows和linux就有不同了。要特別講講才行。

對于windows,采用事件和信號量同步時候,都會使用waitforsingleobject進行等待的,這個函數(shù)的之一個參數(shù)是一個句柄,在這里可以是Event句柄,或Semaphore句柄,第2個參數(shù)就是等待的延遲,最終等多久,單位是ms,如果這個參數(shù)為INFINITE,那么就是無限等待了。釋放信號量的函數(shù)為ReleaseSemaphore();釋放事件的函數(shù)為SetEvent。當然使用這些東西都要初始化的。這里就不講了。Msdn一搜,神馬都出來了,呵呵。神馬都是浮云!

對于linux操作系統(tǒng),是采用條件變量來實現(xiàn)類似的功能的。Linux的條件變量一般都是和互斥鎖一起使用的,主要的函數(shù)有:

pthread_mutex_lock ,

pthread_mutex_unlock,

pthread_cond_init

pthread_cond_signal

pthread_cond_wait

pthread_cond_timewait

為了和windows操作系統(tǒng)進行對比,我用以下表格進行比較:

對照以上表格,總結(jié)如下:

(1) Pthread_cleanup_push,Pthread_cleanup_pop:

這一對函數(shù)push和pop的作用是當出現(xiàn)異常退出時,做一些清除操作,即當在push和pop函數(shù)之間異常退出,包括調(diào)用pthread_exit退出,都會執(zhí)行push里面的清除函數(shù),如果有多個push,注意是是棧,先執(zhí)行后面的那個函數(shù),在執(zhí)行前面的函數(shù),但是注意當在這2個函數(shù)之間通過return 退出的話,執(zhí)不執(zhí)行push后的函數(shù)就看pop函數(shù)中的參數(shù)是不是為0了。還有當沒有異常退出時,等同于在這里面return退出的情況,即:當pop函數(shù)參數(shù)不為0時,執(zhí)行清除操作,當pop函數(shù)參數(shù)為0時,不執(zhí)行push函數(shù)中的清除函數(shù)。

(2)linux的pthread_cond_signal和SetEvent的不同點

Pthread_cond_singal釋放信號后,當沒有Pthread_cond_wait,信號馬上復位了,這點和SetEvent不同,SetEvent是不會復位的。詳解如下:

條件變量的置位和復位有2種常用模型:之一種模型是當條件變量置位時(signaled)以后,如果當前沒有線程在等待,其狀態(tài)會保持為置位(signaled),直到有等待的線程進入被觸發(fā),其狀態(tài)才會變?yōu)閡nsignaled,這種模型以采用Windows平臺上的Auto-set Event 為代表。

第2種模型則是Linux平臺的pthread所采用的模型,當條件變量置位(signaled)以后,即使當前沒有任何線程在等待,其狀態(tài)也會恢復為復位(unsignaled)狀態(tài)。

條件變量在Linux平臺上的這種模型很難說好壞,在實際應(yīng)用中,我們可以對

代碼稍加改進就可以避免這種差異的發(fā)生。由于這種差異只會發(fā)生在觸發(fā)沒有被線程等待在條件變量的時刻,因此我們只需要掌握好觸發(fā)的時機即可。最簡單的做法是增加一個計數(shù)器記錄等待線程的個數(shù),在決定觸發(fā)條件變量前檢查該變量即可。

示例 使用 pthread_cond_wait() 和 pthread_cond_signal()

pthread_mutex_t count_lock;

pthread_cond_t count_nonzero;

unsigned count;

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(&count_lock);

}

(3) 注意Pthread_cond_wait條件返回時互斥鎖的解鎖問題

extern int pthread_cond_wait __P ((pthread_cond_t *__cond,pthread_mutex_t *__mutex));

   調(diào)用這個函數(shù)時,線程解開mutex指向的鎖并被條件變量cond阻塞。線程可以被函數(shù)pthread_cond_signal和函數(shù) pthread_cond_broadcast喚醒線程被喚醒后,它將重新檢查判斷條件是否滿足,如果還不滿足,一般說來線程應(yīng)該仍阻塞在這里,被等待被下一次喚醒。如果在多線程中采用pthread_cond_wait來等待時,會首先釋放互斥鎖,當?shù)却男盘柕絹頃r,再次獲得互斥鎖,因此在之后要注意手動解鎖。舉例如下:

#include

#include

#include

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /*初始化互斥鎖*/

pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //初始化條件變量

void *thread1(void *);

void *thread2(void *);

int i=1;

int main(void)

{

pthread_t t_a;

pthread_t t_b;

pthread_create(&t_a,NULL,thread1,(void *)NULL);/*創(chuàng)建進程t_a*/

pthread_create(&t_b,NULL,thread2,(void *)NULL); /*創(chuàng)建進程t_b*/

pthread_join(t_b, NULL);/*等待進程t_b結(jié)束*/

pthread_mutex_destroy(&mutex);

pthread_cond_destroy(&cond);

exit(0);

}

void *thread1(void *junk)

{

for(i=1;i

{

printf(“IN one\n”);

pthread_mutex_lock(&mutex);//

if(i%3==0)

pthread_cond_signal(&cond);/*,發(fā)送信號,通知t_b進程*/

else

printf(“thead1:%d\n”,i);

pthread_mutex_unlock(&mutex);//*解鎖互斥量*/

printf(“Up Mutex\n”);

sleep(3);

}

}

void *thread2(void *junk)

{

while(i

{

printf(“IN two \n”);

pthread_mutex_lock(&mutex);

if(i%3!=0)

pthread_cond_wait(&cond,&mutex);/*等待*/

printf(“thread2:%d\n”,i);

pthread_mutex_unlock(&mutex);

printf(“Down Mutex\n”);

sleep(3);

}

}

輸出如下:

IN one

thead1:1

Up Mutex

IN two

IN one

thead1:2

Up Mutex

IN one

thread2:3

Down Mutex

Up Mutex

IN one

thead1:4

Up Mutex

IN two

IN one

thead1:5

Up Mutex

IN one

Up Mutex

thread2:6

Down Mutex

IN two

thread2:6

Down Mutex

IN one

thead1:7

Up Mutex

IN one

thead1:8

Up Mutex

IN two

IN one

Up Mutex

thread2:9

Down Mutex

注意藍色的地方,有2個thread2:6,其實當這個程序多執(zhí)行幾次,i=3和i=6時有可能多打印幾個,這里就是競爭鎖造成的了。

(4)另外要注意的Pthread_cond_timedwait等待的是絕對時間,這個和WaitForSingleObject是不同的,Pthread_cond_timedwait在網(wǎng)上也有討論。如下:這個問題比較經(jīng)典,我把它搬過來。

thread_a :

pthread_mutex_lock(&mutex);

//do something

pthread_mutex_unlock(&mutex)

thread_b:

pthread_mutex_lock(&mutex);

//do something

pthread_cond_timedwait(&cond, &mutex, &tm);

pthread_mutex_unlock(&mutex)

有如上兩個線程thread_a, thread_b,現(xiàn)在如果a已經(jīng)進入了臨界區(qū),而b同時超時了,那么b會從pthread_cond_timedwait返回嗎?如果能返回,那豈不是a,b都在臨界區(qū)?如果不能返回,那pthread_cond_timedwait的定時豈不是就不準了?

大家討論有價值的2點如下:

(1) pthread_cond_timedwait (pthread_cond_t *cv, pthread_mutex_t *external_mutex, const struct timespec *abstime) — This function is a time-based variant of pthread_cond_wait. It waits up to abstime amount of time for cv to be notified. If abstime elapses before cv is notified, the function returns back to the caller with an ETIME result, signifying that a timeout has occurred. Even in the case of timeouts, the external_mutex will be locked when pthread_cond_timedwait returns.

(2) 2.1 pthread_cond_timedwait行為和pthread_cond_wait一樣,在返回的時候都要再次lock mutex.

2 .2pthread_cond_timedwait所謂的如果沒有等到條件變量,超時就返回,并不確切。

如果pthread_cond_timedwait超時到了,但是這個時候不能lock臨界區(qū),pthread_cond_timedwait并不會立即返回,但是在pthread_cond_timedwait返回的時候,它仍在臨界區(qū)中,且此時返回值為ETIMEDOUT。

關(guān)于pthread_cond_timedwait超時返回的問題,我也認同觀點2。

附錄:

 int pthread_create(pthread_t *restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *restrict arg);

  返回值:若成功則返回0,否則返回出錯編號

  返回成功時,由tidp指向的內(nèi)存單元被設(shè)置為新創(chuàng)建線程的線程ID。attr參數(shù)用于制定各種不同的線程屬性。新創(chuàng)建的線程從start_rtn函數(shù)的地址開始運行,該函數(shù)只有一個無指針參數(shù)arg,如果需要向start_rtn函數(shù)傳遞的參數(shù)不止一個,那么需要把這些參數(shù)放到一個結(jié)構(gòu)中,然后把這個結(jié)構(gòu)的地址作為arg的參數(shù)傳入。

linux下用C開發(fā)多線程程序,Linux系統(tǒng)下的多線程遵循POSIX線程接口,稱為pthread。

由 restrict 修飾的指針是最初唯一對指針所指向的對象進行存取的方法,僅當?shù)诙€指針基于之一個時,才能對對象進行存取。對對象的存取都限定于基于由 restrict 修飾的指針表達式中。 由 restrict 修飾的指針主要用于函數(shù)形參,或指向由 malloc() 分配的內(nèi)存空間。restrict 數(shù)據(jù)類型不改變程序的語義。 編譯器能通過作出 restrict 修飾的指針是存取對象的唯一方法的假設(shè),更好地優(yōu)化某些類型的例程。

  之一個參數(shù)為指向線程標識符的指針。

  第二個參數(shù)用來設(shè)置線程屬性。

  第三個參數(shù)是線程運行函數(shù)的起始地址。

  第四個參數(shù)是運行函數(shù)的參數(shù)。

因為pthread不是linux系統(tǒng)的庫,所以在編譯時注意加上-lpthread參數(shù),以調(diào)用靜態(tài)鏈接庫。

終止線程:

如果在進程中任何一個線程中調(diào)用exit或_exit,那么整個進行會終止,線程正常的退出方式有:

(1) 線程從啟動例程中返回(return)

(2) 線程可以被另一個進程終止(kill);

(3) 線程自己調(diào)用pthread_exit函數(shù)

#include

pthread_exit

線程等待:

int pthread_join(pthread_t tid,void **rval_ptr)

函數(shù)pthread_join用來等待一個線程的結(jié)束。函數(shù)原型為:

  extern int pthread_join __P (pthread_t __th, void **__thread_return);

之一個參數(shù)為被等待的線程標識符,第二個參數(shù)為一個用戶定義的指針,它可以用來存儲被等待線程的返回值。這個函數(shù)是一個線程阻塞的函數(shù),調(diào)用它的函數(shù)將一直等待到被等待的線程結(jié)束為止,當函數(shù)返回時,被等待線程的資源被收回。

對于windows線程的創(chuàng)建東西,就不列舉了,msdn上 一搜就出來了。呵呵。今天就講到這里吧,希望是拋磚引玉,大家一起探討,呵呵。部分內(nèi)容我也是參考internet的,特此對原作者表示感謝!

在linux中運用多線程知識的介紹就聊到這里吧,感謝你花時間閱讀本站內(nèi)容,更多關(guān)于在linux中運用多線程知識,Linux多線程編程指南:提高程序性能的有效手段,linux 多線程環(huán)境下的幾種鎖機制,淺談linux 多線程編程和 windows 多線程編程的異同的信息別忘了在本站進行查找喔。

創(chuàng)新互聯(lián)(cdcxhl.com)提供穩(wěn)定的云服務(wù)器,香港云服務(wù)器,BGP云服務(wù)器,雙線云服務(wù)器,高防云服務(wù)器,成都云服務(wù)器,服務(wù)器托管。精選鉅惠,歡迎咨詢:028-86922220。


分享名稱:Linux多線程編程指南:提高程序性能的有效手段(在linux中運用多線程知識)
本文地址:http://www.dlmjj.cn/article/djdeeeo.html