2013-03-28 109 views
2

我正在嘗試設置幾個線程來處於等待狀態,直到他們收到pthread_cond_broadcast()pthread播放然後等待?

完成作業後,我想線程返回到他們的等待狀態。

我也想那個叫pthread_cond_broadcast()等待所有線程,然後再繼續回到自己的等待狀態的過程。在這種情況下,它是調用廣播的main()函數。我試圖做的板狀的這個B(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_lockpthread_mutex_tcan_workjobs_donepthread_cond_tjobs_completedbooljobs_completeint

// 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()後立即執行此操作,但這似乎是僵局。

誰能解釋我應如何做這個或者我哪裏錯了?我會很感激任何幫助。

謝謝!

+0

它看起來* *喜歡你試圖etup一堆線程給所有人等待「去」信號,然後它們集中完成NUM_THREAD個作業,理想情況下每個線程一個,並且一旦NUM_THREAD作業完成,返回等待另一個去信號。這是否準確?我已經看到不少於五個錯誤,但是想要在確定答案之前確切地知道你想要做什麼。 – WhozCraig 2013-03-28 07:48:58

+0

@WhozCraig,是的,這是我正在嘗試做的。我還希望調用「發送」信號的功能在繼續之前等待所有作業完成。 – noko 2013-03-28 08:04:06

回答

1

你有你的函數結束,這將導致未定義行爲3個可能的連續調用pthread_mutex_unlock。你其實不需要兩個內在的。如果jobs_completetrue,該線程將退出循環,解除鎖定,否則就會陷入循環,需要它的can_work條件等待。

此外,還有

pthread_cond_wait(&jobs_complete); 

你大概的意思:

pthread_cond_wait(&jobs_complete,&job_lock); 

此外,該功能需要一個pthread_cond_t *pthread_mutex_t *,不是int,所以即使那麼代碼是明顯的打破。

請注意,條件變量上的信號或廣播只會對等待變量的線程已有產生影響。信號不會保留以備將來等待。 因此,當線程在jobs_complete上循環時阻塞並再次等待,它們將不得不再次發信號以恢復工作。

另一件事:你所提到的類型的job_completeintjob_completedbool,但你的代碼似乎並不同意:

 if(jobs_completed == NUM_THREADS) 
     { 
      jobs_complete = true; 

這裏是我的建議:學習上的信號燈和阻隔抽象模型,如果可以的話,使用現有的實現方式(在C booststd ++ 11),或使用pthread API否則重新實現它們。這些將比操縱cond變量更容易幫助你處理這種情況。看看這個網站上的現有解決方案。例如this question涉及一個非常類似的問題,我提供的解決方案可以很容易地修改爲使用pthread API來滿足您的要求。

3

我只是張貼這(這幾乎是所有的C代碼,但這樣是並行線程,所以有點鬆弛懇請)證明做我認爲你想實現的一種方式。很明顯,你會想要正確地將這些內容封裝在適當的類中等等。希望能夠告訴你的是,謂詞管理和通知的條件變量,互斥鎖以及它們與的關係是如何工作的。

我希望你覺得它有用。祝你有美好的一天。

#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