![](/img/trans.png)
[英]When is it more appropriate to use a pthread barrier instead of a condition wait and broadcast?
[英]pthread broadcast and then wait?
我正在嘗試設置幾個線程以處於等待狀態,直到它們收到pthread_cond_broadcast()
。
完成一項工作后,我希望線程回到等待狀態。
我還希望調用pthread_cond_broadcast()
的進程在繼續之前等待所有線程返回其等待狀態。 在這種情況下,它是調用廣播的main()函數。 我正在嘗試做這個b有main(0在調用廣播后做一個pthread_cond_wait()
。
void* Work::job(void* id)
{
int idx = (long)id;
while(1)
{
pthread_mutex_lock(&job_lock);
while(!jobs_complete)
{
// wait for main to broadcast
pthread_cond_wait(&can_work, &job_lock);
pthread_mutex_unlock(&job_lock);
// work here
pthread_mutex_lock(&job_lock);
++jobs_completed;
if(jobs_completed == NUM_THREADS)
{
jobs_complete = true;
pthread_cond_signal(&jobs_done);
pthread_mutex_unlock(&job_lock);
}
pthread_mutex_unlock(&job_lock);
}
pthread_mutex_unlock(&job_lock);
}
return NULL;
}
NUM_THREADS為4, job_lock為pthread_mutex_t
, can_work和jobs_done為pthread_cond_t
, jobs_completed為bool
, jobs_complete為int
。
// work
jobs_completed = false;
jobs_complete = 0;
pthread_mutex_lock(&job_lock);
pthread_cond_broadcast(&can_work);
pthread_cond_wait(&jobs_complete);
pthread_mutex_unlock(&job_lock);
// work that depends on jobs_complete
現在,我現在這樣做的權利,通過調用pthread_cond_broadcast()
然后pthread_cond_wait()
之后,但這個好像死鎖。
任何人都可以解釋我應該如何做這個或我出錯的地方? 我很感激你的幫助。
謝謝!
我只發布這個(這幾乎都是C代碼,但pthreads也是如此,所以請求一點松弛)來演示一種做我認為你想要完成的事情的方法。 顯然,您希望將大部分內容正確地封裝在適當的類中等。這有望向您展示條件變量,互斥體及其與謂詞管理和通知的關系是如何工作的。
希望對你有幫助。 祝你有美好的一天。
#include <iostream>
#include <unistd.h>
#include <pthread.h>
using namespace std;
// our global condition variable and mutex
pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
// our predicate values.
bool finished = false;
int jobs_waiting = 0;
int jobs_completed = 0;
// our thread proc
static void *worker_proc(void* p)
{
intptr_t id = (intptr_t)p; // our id
size_t n_completed = 0; // our job completion count
// always latch prior to eval'ing predicate vars.
pthread_mutex_lock(&mtx);
while (!finished)
{
// wait for finish or work-waiting predicate
while (!finished && jobs_waiting == 0)
pthread_cond_wait(&cv, &mtx);
// we own the mutex, so we're free to look at, modify
// etc. the values(s) that we're using for our predicate
if (finished)
break;
// must be a job_waiting, reduce that number by one, then
// unlock the mutex and start our work. Note that we're
// changing the predicate (jobs_waiting is part of it) and
// we therefore need to let anyone that is monitoring know.
--jobs_waiting;
pthread_cond_broadcast(&cv);
pthread_mutex_unlock(&mtx);
// DO WORK HERE (this just runs a lame summation)
for (int i=0,x=0;i<1048576; x += ++i);
++n_completed;
// finished work latch mutex and setup changes
pthread_mutex_lock(&mtx);
++jobs_completed;
pthread_cond_broadcast(&cv);
}
// final report
cout << id << ": jobs completed = " << n_completed << endl;
// we always exit owning the mutex, so unlock it now. but
// let anyone else know they should be quitting as well.
pthread_cond_broadcast(&cv);
pthread_mutex_unlock(&mtx);
return p;
}
// sets up a batch of work and waits for it to finish.
void run_batch(int num)
{
pthread_mutex_lock(&mtx);
jobs_waiting = num;
jobs_completed = 0;
pthread_cond_broadcast(&cv);
// wait or all jobs to complete.
while (jobs_completed != num)
pthread_cond_wait(&cv, &mtx);
// we own this coming out, so let it go.
pthread_mutex_unlock(&mtx);
}
// main entry point.
int main()
{
// number of threads in our crew
static const size_t N = 7;
pthread_t thrds[N] = {0};
// startup thread crew.
intptr_t id = 0;
for (size_t i=0; i<N; ++i)
pthread_create(thrds + i, NULL, worker_proc, (void*)(++id));
// run through batches. each batch is one larger
// than the prior batch. this should result in some
// interesting job-counts per-thread.
for (int i=0; i<64; ++i)
run_batch(i);
// flag for shutdown state.
pthread_mutex_lock(&mtx);
finished = true;
pthread_cond_broadcast(&cv);
pthread_mutex_unlock(&mtx);
for (size_t i=0; i<N; pthread_join(thrds[i++], NULL));
return 0;
}
樣本輸出#1
3: jobs completed = 256
6: jobs completed = 282
5: jobs completed = 292
2: jobs completed = 242
1: jobs completed = 339
4: jobs completed = 260
7: jobs completed = 409
樣本輸出#2
6: jobs completed = 882
1: jobs completed = 210
4: jobs completed = 179
5: jobs completed = 178
2: jobs completed = 187
7: jobs completed = 186
3: jobs completed = 194
樣本輸出#3
1: jobs completed = 268
6: jobs completed = 559
3: jobs completed = 279
5: jobs completed = 270
2: jobs completed = 164
4: jobs completed = 317
7: jobs completed = 159
固定批量大小
相同的代碼,但更改此:
for (int i=0; i<64; ++i)
run_batch(i);
對此:
for (int i=0; i<64; ++i)
run_batch(N);
給出以下內容,這可能更接近您真正想要的內容。
樣本輸出#1
4: jobs completed = 65
2: jobs completed = 63
5: jobs completed = 66
3: jobs completed = 63
1: jobs completed = 64
7: jobs completed = 63
6: jobs completed = 64
樣本輸出#2
3: jobs completed = 65
5: jobs completed = 62
1: jobs completed = 67
7: jobs completed = 63
2: jobs completed = 65
6: jobs completed = 61
4: jobs completed = 65
樣本輸出#3
2: jobs completed = 58
4: jobs completed = 61
5: jobs completed = 69
7: jobs completed = 68
3: jobs completed = 61
1: jobs completed = 64
6: jobs completed = 67
在函數末尾有3個可能的連續調用pthread_mutex_unlock
,這將導致未定義的行為。 你實際上並不需要兩個內在的。 如果jobs_complete
為true
,則線程將退出循環並釋放鎖定,否則它將循環並需要它來等待can_work
條件。
還有,那里
pthread_cond_wait(&jobs_complete);
你可能意味着:
pthread_cond_wait(&jobs_complete,&job_lock);
此外,該函數需要一個pthread_cond_t *
和一個pthread_mutex_t *
,而不是一個int
,所以即使這樣,代碼也明顯被破壞了。
要知道,一個信號或條件變量廣播只會對已經在等待此變量線程的效果。 信號不會保留以供將來等待。 因此,當線程在jobs_complete
時再次循環jobs_complete
並再次等待時,必須再次發出信號以恢復工作。
另一件事:你提到job_complete
的類型為int
, job_completed
為bool
,但你的代碼似乎不同意:
if(jobs_completed == NUM_THREADS)
{
jobs_complete = true;
這是我的建議:學習信號量和屏障抽象模型,如果可以的話,使用現有的實現(C ++ 11中的boost
或std
),或者使用pthread
API重新實現它們。 這些將幫助您比操縱cond變量更容易處理這種情況。 在這個網站上查找現有解決方案。 例如, 這個問題涉及一個非常類似的問題,我提供的解決方案可以很容易地修改,以使用pthread API來滿足您的要求。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.