日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java线程条件变量_使用条件变量(多线程笔记)

發布時間:2024/9/27 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java线程条件变量_使用条件变量(多线程笔记) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

條件變量屬性:

使用條件變量可以以原子方式阻塞線程,知道某個特定條件為真為止。條件變量始終與互斥鎖一起使用。

使用條件變量,線程可以以原子方式阻塞,知道滿足某個條件為止。對掉件的測試時在互斥鎖的保護下進行的。

如果條件為假,縣城通常會給予條件變量則阻塞,并于原子方式釋放等待條件變化的互斥鎖。如果一個線程更改了條件,該線程可能會向相關的條件變量發出信號,從而是一個或多個等待的線程執行以下操作:

喚醒

再次獲取互斥鎖

重新評估條件

以下情況下,條件變量可用于在進程之間同步線程:

線程是在可以寫入的內存中分配的

內存由協作進程共享

調度策略可確定喚醒阻塞線程的方式,對于缺省值,按照優先級順序喚醒線程。

必須設置和初始化條件變量的屬性,然后才能使用條件變量。

初始化條件變量屬性:

使用pthread_condattr_init(3C) 可以將與該對象相關聯的屬性初始化為其缺省值。在執行過程中,線程系統會為每個屬性對象分配存儲空間。

pthread_condattr_init語法

int pthread_cond_init(pthread_cond_t *ptr ?, const othread_condattr_t *av);

cattr 設置為NULL。將cattr 設置為NULL 與傳遞缺省條件變量屬性對象的地址等效,但是

沒有內存開銷。

使用PTHREAD_COND_INITIALIZER?宏可以將以靜態方式定義的條件變量初始化為其缺省

屬性。PTHREAD_COND_INITIALIZER宏與動態分配具有null 屬性的pthread_cond_init()

等效,但是不進行錯誤檢查。

多個線程決不能同時初始化或重新初始化同一個條件變量。如果要重新初始化或銷毀

某個條件變量,則應用程序必須確保該條件變量未被使用。

pthread_cond_init返回值

pthread_cond_init()在成功完成之后會返回零。其他任何返回值都表示出現了錯誤。

如果出現以下任一情況,該函數將失敗并返回對應的值。

EINVAL

描述: cattr 指定的值無效。

EBUSY

描述: 條件變量處于使用狀態。

EAGAIN

描述: 必要的資源不可用。

ENOMEM

描述: 內存不足,無法初始化條件變量。

基于條件變量阻塞

使用pthread_cond_wait(3C)可以以原子方式釋放mp 所指向的互斥鎖,并導致調用線

程基于cv 所指向的條件變量阻塞。

pthread_cond_wait?語法

int pthread_cond_wait(pthread_cond_t *cv,pthread_mutex_t *mutex);

1

2

#include pthread_cond_t cv;

pthread_mutex_t mp;int ret;

/* wait on condition variable */ret = pthread_cond_wait(&cv, &mp);

阻塞的線程可以通過pthread_cond_signal()?或pthread_cond_broadcast()喚醒,也可

以在信號傳送將其中斷時喚醒。

不能通過pthread_cond_wait()?的返回值來推斷與條件變量相關聯的條件的值的任何變

化。必須重新評估此類條件。

pthread_cond_wait()例程每次返回結果時調用線程都會鎖定并且擁有互斥鎖,即使返

回錯誤時也是如此。

該條件獲得信號之前,該函數一直被阻塞。該函數會在被阻塞之前以原子方式釋放相

關的互斥鎖,并在返回之前以原子方式再次獲取該互斥鎖。

通常,對條件表達式的評估是在互斥鎖的保護下進行的。如果條件表達式為假,線程

會基于條件變量阻塞。然后,當該線程更改條件值時,另一個線程會針對條件變量發

出信號。這種變化會導致所有等待該條件的線程解除阻塞并嘗試再次獲取互斥鎖。

必須重新測試導致等待的條件,然后才能從pthread_cond_wait()處繼續執行。喚醒的

線程重新獲取互斥鎖并從pthread_cond_wait()返回之前,條件可能會發生變化。等待

線程可能并未真正喚醒。建議使用的測試方法是,將條件檢查編寫為調用

pthread_cond_wait()?的while()循環。

pthread_mutex_lock();

while(condition_is_false)

pthread_cond_wait();

pthread_mutex_unlock();

如果有多個線程基于該條件變量阻塞,則無法保證按特定的順序獲取互斥鎖。

注–?pthread_cond_wait()?是取消點。如果取消處于暫掛狀態,并且調用線程啟用了取

消功能,則該線程會終止,并在繼續持有該鎖的情況下開始執行清除處理程序。

pthread_cond_wait?返回值

pthread_cond_wait()在成功完成之后會返回零。其他任何返回值都表示出現了錯誤。

如果出現以下情況,該函數將失敗并返回對應的值。

EINVAL

描述: cv 或mp 指定的值無效。

解除阻塞一個線程

對于基于cv 所指向的條件變量阻塞的線程,使用pthread_cond_signal(3C)可以解除阻

塞該線程。

pthread_cond_signal語法

int pthread_cond_signal(pthread_cond_t *cv);

1

2

#include pthread_cond_t cv;int ret;/* one condition variable is signaled */ret = pthread_cond_signal(&cv);

應在互斥鎖的保護下修改相關條件,該互斥鎖用于獲得信號的條件變量中。否則,可

能在條件變量的測試和pthread_cond_wait()阻塞之間修改該變量,這會導致無限期等

待。

調度策略可確定喚醒阻塞線程的順序。對于SCHED_OTHER,將按優先級順序喚醒線程。

如果沒有任何線程基于條件變量阻塞,則調用pthread_cond_signal()?不起作用。

示例 使用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);

}

pthread_cond_signal返回值

pthread_cond_signal()在成功完成之后會返回零。其他任何返回值都表示出現了錯

誤。如果出現以下情況,該函數將失敗并返回對應的值。

EINVAL

描述: cv 指向的地址非法。

示例 說明了如何使用pthread_cond_wait()和pthread_cond_signal()。

在指定的時間之前阻塞

pthread_cond_timedwait(3C)?的用法與pthread_cond_wait()的用法基本相同,區別在

于在由abstime 指定的時間之后pthread_cond_timedwait()不再被阻塞。

pthread_cond_timedwait語法

int pthread_cond_timedwait(pthread_cond_t *cv,

pthread_mutex_t *mp, const struct timespec *abstime);

1

2

3

#include #include pthread_cond_t cv;

pthread_mutex_t mp;

timestruct_t abstime;int ret;/* wait on condition variable */ret = pthread_cond_timedwait(&cv, &mp, &abstime);

1

2

3

4

5

6

7

8

9

pthread_cond_timewait()每次返回時調用線程都會鎖定并且擁有互斥鎖,即使

pthread_cond_timedwait()返回錯誤時也是如此。

pthread_cond_timedwait()?函數會一直阻塞,直到該條件獲得信號,或者最后一個參數

所指定的時間已過為止。

注–?pthread_cond_timedwait()也是取消點。

示例計時條件等待

pthread_timestruc_t to;

pthread_mutex_t m;

pthread_cond_t c;

...

pthread_mutex_lock(&m);

to.tv_sec = time(NULL) + TIMEOUT;

to.tv_nsec = 0;

while (cond == FALSE) {

err = pthread_cond_timedwait(&c, &m, &to);

if (err == ETIMEDOUT) {

/* timeout, do something */

break;

}

}

pthread_mutex_unlock(&m);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

pthread_cond_timedwait?返回值

pthread_cond_timedwait()?在成功完成之后會返回零。其他任何返回值都表示出現了錯

誤。如果出現以下任一情況,該函數將失敗并返回對應的值。

EINVAL

描述: cv 或abstime 指向的地址非法。

ETIMEDOUT

描述: abstime 指定的時間已過。

超時會指定為當天時間,以便在不重新計算值的情況下高效地重新測試條件,如示例

中所示。

在指定的時間間隔內阻塞

pthread_cond_reltimedwait_np(3C)?的用法與pthread_cond_timedwait()的用法基本相

同,唯一的區別在于pthread_cond_reltimedwait_np()會采用相對時間間隔而不是將來

的絕對時間作為其最后一個參數的值。

pthread_cond_reltimedwait_np語法

int pthread_cond_reltimedwait_np(pthread_cond_t *cv, pthread_mutex_t *mp,

const struct timespec *reltime);

1

2

3

#include #include pthread_cond_t cv;

pthread_mutex_t mp;

timestruct_t reltime;int ret;/* wait on condition variable */ret = pthread_cond_reltimedwait_np(&cv, &mp, &reltime);

1

2

3

4

5

6

7

8

pthread_cond_reltimedwait_np()?每次返回時調用線程都會鎖定并且擁有互斥鎖,即使

pthread_cond_reltimedwait_np()返回錯誤時也是如此。pthread_cond_reltimedwait_np()函數會一直阻塞,直到該條件獲得信號,或者最后一個參數指定的時間間隔已過為止。

注–?pthread_cond_reltimedwait_np()也是取消點。

pthread_cond_reltimedwait_np返回值

pthread_cond_reltimedwait_np()在成功完成之后會返回零。其他任何返回值都表示出

現了錯誤。如果出現以下任一情況,該函數將失敗并返回對應的值。

EINVAL

描述: cv 或reltime 指示的地址非法。

ETIMEDOUT

描述: reltime 指定的時間間隔已過。

解除阻塞所有線程

對于基于cv 所指向的條件變量阻塞的線程,使用pthread_cond_broadcast(3C)可以解

除阻塞所有這些線程,這由pthread_cond_wait()來指定。

pthread_cond_broadcast 語法

int pthread_cond_broadcast(pthread_cond_t *cv);

1

2

#include pthread_cond_t cv;int ret;

/* all condition variables are signaled */ret = pthread_cond_broadcast(&cv);

1

2

3

4

5

6

如果沒有任何線程基于該條件變量阻塞,則調用pthread_cond_broadcast()不起作

用。

由于pthread_cond_broadcast()?會導致所有基于該條件阻塞的線程再次爭用互斥鎖,

因此請謹慎使用pthread_cond_broadcast()。例如,通過使用

pthread_cond_broadcast(),線程可在資源釋放后爭用不同的資源量,如示例 中

所示。

示例條件變量廣播

pthread_mutex_t rsrc_lock;

pthread_cond_t rsrc_add;unsigned int resources;

get_resources(int amount)

{

pthread_mutex_lock(&rsrc_lock);

while (resources < amount) {

pthread_cond_wait(&rsrc_add, &rsrc_lock);

}

resources -= amount;

pthread_mutex_unlock(&rsrc_lock);

}

add_resources(int amount)

{

pthread_mutex_lock(&rsrc_lock);

resources += amount;

pthread_cond_broadcast(&rsrc_add);

pthread_mutex_unlock(&rsrc_lock);

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

請注意,在add_resources()中,首先更新resources 還是首先在互斥鎖中調用

pthread_cond_broadcast()無關緊要。

應在互斥鎖的保護下修改相關條件,該互斥鎖用于獲得信號的條件變量中。否則,可

能在條件變量的測試和pthread_cond_wait()阻塞之間修改該變量,這會導致無限期等

待。

pthread_cond_broadcast?返回值

pthread_cond_broadcast()在成功完成之后會返回零。其他任何返回值都表示出現了錯

誤。如果出現以下情況,該函數將失敗并返回對應的值。

EINVAL

描述: cv 指示的地址非法。

銷毀條件變量狀態

使用pthread_cond_destroy(3C)?可以銷毀與cv 所指向的條件變量相關聯的任何狀態。

pthread_cond_destroy?語法

int pthread_cond_destroy(pthread_cond_t *cv);

1

2

#include pthread_cond_t cv;int ret;

/* Condition variable is destroyed */ret = pthread_cond_destroy(&cv);

1

2

3

4

5

6

請注意,沒有釋放用來存儲條件變量的空間。

pthread_cond_destroy返回值

pthread_cond_destroy()在成功完成之后會返回零。其他任何返回值都表示出現了錯

誤。如果出現以下情況,該函數將失敗并返回對應的值。

EINVAL

描述: cv 指定的值無效。

喚醒丟失問題

如果線程未持有與條件相關聯的互斥鎖,則調用pthread_cond_signal()?或

pthread_cond_broadcast()會產生喚醒丟失錯誤。

滿足以下所有條件時,即會出現喚醒丟失問題:

■ 一個線程調用pthread_cond_signal()或pthread_cond_broadcast()

■ 另一個線程已經測試了該條件,但是尚未調用pthread_cond_wait()

■ 沒有正在等待的線程信號不起作用,因此將會丟失,僅當修改所測試的條件但未持有

與之相關聯的互斥鎖時,才會出現此問題。只要僅在持有關聯的互斥鎖同時修改所測試

的條件,即可調用pthread_cond_signal()?和pthread_cond_broadcast(),

而無論這些函數是否持有關聯的互斥鎖。

生成方和使用者問題

并發編程中收集了許多標準的眾所周知的問題,生成方和使用者問題只是其中的一個

問題。此問題涉及到一個大小限定的緩沖區和兩類線程(生成方和使用者),生成方

將項放入緩沖區中,然后使用者從緩沖區中取走項。

生成方必須在緩沖區中有可用空間之后才能向其中放置內容。使用者必須在生成方向

緩沖區中寫入之后才能從中提取內容。

條件變量表示一個等待某個條件獲得信號的線程隊列。

示例中包含兩個此類隊列。一個隊列(less) 針對生成方,用于等待緩沖區中出現空

位置。另一個隊列(more) 針對使用者,用于等待從緩沖槽位的空位置中提取其中包含

的信息。該示例中還包含一個互斥鎖,因為描述該緩沖區的數據結構一次只能由一個

線程訪問。

示例生成方和使用者的條件變量問題

typedef struct {

char buf[BSIZE];

int occupied;

int nextin;

int nextout;

pthread_mutex_t mutex;

pthread_cond_t more;

pthread_cond_t less;

} buffer_t;

buffer_t buffer;

1

2

3

4

5

6

7

8

9

10

如示例 中所示,生成方線程獲取該互斥鎖以保護buffer 數據結構,然后,緩沖區

確定是否有空間可用于存放所生成的項。如果沒有可用空間,生成方線程會調用

pthread_cond_wait()。pthread_cond_wait()會導致生成方線程連接正在等待less 條件

獲得信號的線程隊列。less 表示緩沖區中的可用空間。

與此同時,在調用pthread_cond_wait()的過程中,該線程會釋放互斥鎖的鎖定。正在

等待的生成方線程依賴于使用者線程在條件為真時發出信號,如示例 中所示。該

條件獲得信號時,將會喚醒等待less 的第一個線程。但是,該線程必須再次鎖定互斥

鎖,然后才能從pthread_cond_wait()返回。

獲取互斥鎖可確保該線程再次以獨占方式訪問緩沖區的數據結構。該線程隨后必須檢

查緩沖區中是否確實存在可用空間。如果空間可用,該線程會向下一個可用的空位置

中進行寫入。

與此同時,使用者線程可能正在等待項出現在緩沖區中。這些線程正在等待條件變量

more。剛在緩沖區中存儲內容的生成方線程會調用pthread_cond_signal()?以喚醒下一

個正在等待的使用者。如果沒有正在等待的使用者,此調用將不起作用。

最后,生成方線程會解除鎖定互斥鎖,從而允許其他線程處理緩沖區的數據結構。

示例生成方和使用者問題:生成方

void producer(buffer_t *b, char item)

{

pthread_mutex_lock(&b->mutex);

while (b->occupied >= BSIZE)

pthread_cond_wait(&b->less, &b->mutex);

assert(b->occupied < BSIZE);

b->buf[b->nextin++] = item;

b->nextin %= BSIZE;

b->occupied++;

/* now: either b->occupied < BSIZE and b->nextin is the index

of the next empty slot in the buffer, or

b->occupied == BSIZE and b->nextin is the index of the

next (occupied) slot that will be emptied by a consumer

(such as b->nextin == b->nextout) */

pthread_cond_signal(&b->more);

pthread_mutex_unlock(&b->mutex);

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

請注意assert()語句的用法。除非在編譯代碼時定義了NDEBUG,否則assert()?在其參

數的計算結果為真(非零)時將不執行任何操作。如果參數的計算結果為假(零),

則該程序會中止。在多線程程序中,此類斷言特別有用。如果斷言失敗,assert()會

立即指出運行時問題。assert()?還有另一個作用,即提供有用的注釋。

以/* now: either b->occupied ...開頭的注釋最好以斷言形式表示,但是由于語句過

于復雜,無法用布爾值表達式來表示,因此將用英語表示。

斷言和注釋都是不變量的示例。這些不變量是邏輯語句,在程序正常執行時不應將其

聲明為假,除非是線程正在修改不變量中提到的一些程序變量時的短暫修改過程中。

當然,只要有線程執行語句,斷言就應當為真。

使用不變量是一種極為有用的方法。即使沒有在程序文本中聲明不變量,在分析程序

時也應將其視為不變量。

每次線程執行包含注釋的代碼時,生成方代碼中表示為注釋的不變量始終為真。如果

將此注釋移到緊挨mutex_unlock()的后面,則注釋不一定仍然為真。如果將此注釋移

到緊跟assert()之后的位置,則注釋仍然為真。

因此,不變量可用于表示一個始終為真的屬性,除非一個生成方或一個使用者正在更

改緩沖區的狀態。線程在互斥鎖的保護下處理緩沖區時,該線程可能會暫時聲明不變

量為假。但是,一旦線程結束對緩沖區的操作,不變量即會恢復為真。

示例給出了使用者的代碼。該邏輯流程與生成方的邏輯流程相對稱。

示例生成方和使用者問題:使用者

char consumer(buffer_t *b)

{

char item;

pthread_mutex_lock(&b->mutex);

while(b->occupied <= 0)

pthread_cond_wait(&b->more, &b->mutex);

assert(b->occupied > 0);

item = b->buf[b->nextout++];

b->nextout %= BSIZE;

b->occupied--;

/* now: either b->occupied > 0 and b->nextout is the index

of the next occupied slot in the buffer, or

b->occupied == 0 and b->nextout is the index of the next

(empty) slot that will be filled by a producer (such as

b->nextout == b->nextin) */

pthread_cond_signal(&b->less);

pthread_mutex_unlock(&b->mutex);

return(item);

}

總結

以上是生活随笔為你收集整理的java线程条件变量_使用条件变量(多线程笔记)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。