简体   繁体   English

pthread广播然后等待?

[英]pthread broadcast and then wait?

I'm trying to set up several threads to sit in a wait state until they receive a pthread_cond_broadcast() . 我正在尝试设置几个线程以处于等待状态,直到它们收到pthread_cond_broadcast()

After completing a job, I want the threads to go back into their wait states. 完成一项工作后,我希望线程回到等待状态。

I also want the process that called the pthread_cond_broadcast() to wait for all of the threads to return to their wait states before continuing. 我还希望调用pthread_cond_broadcast()的进程在继续之前等待所有线程返回其等待状态。 In this case, it's the main() function that calls broadcast. 在这种情况下,它是调用广播的main()函数。 I'm trying to do this b having main(0 do a pthread_cond_wait() after calling a broadcast. 我正在尝试做这个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 is 4, job_lock is a pthread_mutex_t , can_work and jobs_done are pthread_cond_t , jobs_completed is a bool and jobs_complete is an int . 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

Right now, I'm doing this right now by calling pthread_cond_broadcast() and then pthread_cond_wait() right after it but this seems to deadlock. 现在,我现在这样做的权利,通过调用pthread_cond_broadcast()然后pthread_cond_wait()之后,但这个好像死锁。

Can anyone explain how I should be doing this or where I went wrong? 任何人都可以解释我应该如何做这个或我出错的地方? I'd appreciate any assistance. 我很感激你的帮助。

Thanks! 谢谢!

I'm only posting this (which is almost all C code, but so is pthreads, so a little slack is kindly requested) to demonstrate one way of doing what I think you're trying to accomplish. 我只发布这个(这几乎都是C代码,但pthreads也是如此,所以请求一点松弛)来演示一种做我认为你想要完成的事情的方法。 Obviously you would want to properly encapsulate most of this in proper classes etc. What this is hopefully going to show you is how condition variables, mutex, and their relationship with predicate management and notification works. 显然,您希望将大部分内容正确地封装在适当的类中等。这有望向您展示条件变量,互斥体及其与谓词管理和通知的关系是如何工作的。

I hope you find it useful. 希望对你有帮助。 Have a great day. 祝你有美好的一天。

#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;
}

Sample Output #1 样本输出#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

Sample Output #2 样本输出#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

Sample Output #3 样本输出#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

Fixed Batch Sizes 固定批量大小

The same code, but changing this: 相同的代码,但更改此:

for (int i=0; i<64; ++i)
    run_batch(i);

to this: 对此:

for (int i=0; i<64; ++i)
    run_batch(N);

gives the following, which is probably even closer to what you're really looking for. 给出以下内容,这可能更接近您真正想要的内容。

Sample Output #1 样本输出#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

Sample Output #2 样本输出#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

Sample Output #3 样本输出#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

You have 3 possible successive calls to pthread_mutex_unlock at the end of your function, which would result in undefined behaviour. 在函数末尾有3个可能的连续调用pthread_mutex_unlock ,这将导致未定义的行为。 You actually don't need the two inner ones. 你实际上并不需要两个内在的。 If jobs_complete is true , the thread will exit the loop and release the lock, otherwise it will loop and need it for the wait on the can_work condition. 如果jobs_completetrue ,则线程将退出循环并释放锁定,否则它将循环并需要它来等待can_work条件。

Also, there 还有,那里

 pthread_cond_wait(&jobs_complete);

you probably mean: 你可能意味着:

pthread_cond_wait(&jobs_complete,&job_lock);

Besides, that function expects a pthread_cond_t * and a pthread_mutex_t * , not an int , so even then that code is clearly broken. 此外,该函数需要一个pthread_cond_t *和一个pthread_mutex_t * ,而不是一个int ,所以即使这样,代码也明显被破坏了。

Be aware that a signal or a broadcast on a condition variable will only have an effect on threads already waiting on the variable. 要知道,一个信号或条件变量广播只会对已经在等待此变量线程的效果。 The signal is not retained for future wait. 信号不会保留以供将来等待。 So when the threads loop on jobs_complete while block and wait again, they will have to be signaled again to resume work. 因此,当线程在jobs_complete时再次循环jobs_complete并再次等待时,必须再次发出信号以恢复工作。

Another thing: you mention the types of job_complete as int and job_completed as bool , yet your code doesn't seem to agree: 另一件事:你提到job_complete的类型为intjob_completedbool ,但你的代码似乎不同意:

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

Here's my advice: learn on the semaphore and barrier abstract models, and if you can, use the existing implementations ( boost or std in C++11), or reimplement them using the pthread API otherwise. 这是我的建议:学习信号量和屏障抽象模型,如果可以的话,使用现有的实现(C ++ 11中的booststd ),或者使用pthread API重新实现它们。 Those will help you handle the situation much more easily than manipulating cond variables. 这些将帮助您比操纵cond变量更容易处理这种情况。 Look on this very website for existing solutions. 在这个网站上查找现有解决方案。 For example this question deals with a very similar problem, and the solution I provided can be easily modified to use the pthread API to match your requirement. 例如, 这个问题涉及一个非常类似的问题,我提供的解决方案可以很容易地修改,以使用pthread API来满足您的要求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM