【问题标题】:Synchronisation before pthread_cond_broadcastpthread_cond_broadcast 之前的同步
【发布时间】:2017-03-10 15:17:03
【问题描述】:

我想从主线程向等待条件的所有其他线程发送广播信号。在我看来,广播信号在线程中来得早。

#include <iostream>
#include <pthread.h>

#define NUM 4
#define SIZE 256

using namespace std;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_barrier_t barrier;

class cache{
    int lv1;
public:
    int write(int i){
        lv1=i;
        pthread_cond_broadcast(&cond);
    }
};

cache c[NUM];

void *thread(void *arg){
   int i = (int)arg;
   for(;;){
       pthread_mutex_lock(&mutex);
       pthread_cond_wait(&cond,&mutex);
       cout << "Thread: "<< i << endl;
       //do some work
       pthread_mutex_unlock(&mutex);
   }
}


int main()
{
    pthread_t tid[NUM];
    pthread_barrier_init(&barrier,NULL,NUM+1);

    for(int i=0;i<NUM;i++){
        pthread_create(&tid[i],NULL,thread,(void*)i);
    }

    //Sleep(2);
    c[0].write(55);  //broadcast signal
    //Sleep(2);
    c[1].write(44);  //broadcast signal

    for(int i=0;i<NUM;i++){
        pthread_join(tid[i],NULL);
    }

    cout << "Hello world!" << endl;
    return 0;
}

如果我在主函数中插入 Sleep(2),它可以工作,但我不想在调用 pthread_broadcast 之前等待时间而是同步。 我想到了一个障碍,但是 pthread_cond_wait 是阻塞的,对吧?

【问题讨论】:

  • 请注意:为什么不使用标准的 -library?
  • 感谢注解,以后我会看看标准的
  • @TomNeumeier 如果您使用的是 ubuntu,请安装 glibc-doc pkg 并仔细阅读 pthread_cond_signal/broadcast 的手册页。通常,您在锁定下修改谓词,然后广播或向等待线程发出信号。请注意,pthread_cond_wait 可能会被虚假唤醒,因此您需要重新检查持有 mutex 的谓词(您在 wakepu 上自动获取 mtx)。

标签: c++ synchronization pthreads


【解决方案1】:

您需要了解如何使用条件变量。您还错误地处理了线程的整数参数。这是一个固定版本,希望与您想要的相似:

#include <iostream>
#include <pthread.h>
#include <unistd.h>

#define NUM 4
#define SIZE 256

using namespace std;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_barrier_t barrier;

class cache{
    int lv1;
public:
    int write(int i) { lv1=i; }
    const int val() { return lv1; }
};

cache c[NUM];

void *thread(void *arg)
{
    int i = *(int*)arg;
    for(;;) {
        pthread_mutex_lock(&mutex);
        // Check predicate, do not go to sleep if predicate is fulfilled                                                                                                                                                                                                                                                                                                                    
        if (c[0].val() > 0 && c[1].val() > 0) {
            cout << "Thread " << i << " leaving...\n";
            pthread_mutex_unlock(&mutex);
            return 0;
        }
        pthread_cond_wait(&cond, &mutex);
        cout << "Thread wakeup: "<< i << endl;
        // do some work                                                                                                                                                                                                                                                                                                                                                                     
        pthread_mutex_unlock(&mutex);
    }
}


int main()
{
    pthread_t tid[NUM];

    int arg[NUM];
    for(int i=0; i<NUM; i++) {
        arg[i] = i; // make a copy of i used by only one thread                                                                                                                                                                                                                                                                                                                             
        pthread_create(&tid[i], NULL, thread,(void*)&arg[i]);
    }

    pthread_mutex_lock(&mutex);
    c[0].write(55);
    c[1].write(44);
    pthread_mutex_unlock(&mutex);
    pthread_cond_broadcast(&cond); // Signal all threads that predicate is fulfilled                                                                                                                                                                                                                                                                                                        


    for(int i=0; i<NUM; i++) {
        pthread_join(tid[i],NULL);
        cout << "Joined " << i << '\n';
    }

    cout << "Hello world!" << endl;
    return 0;
}

【讨论】:

  • 非常感谢您的回答,我现在明白了谓词是如何使用的。我现在想说明我的问题:我正在通过变量编写总线通信。每次写入缓存类的实例后,我都需要调用所有线程,期望与该类关联的一个线程,我已经在类中执行了线程函数。所以这就像我写入或读取一个变量,然后向我写入该变量的所有其他线程发出信号
  • @TomNeumeier 很高兴为您提供帮助。此外,正如建议的那样,最好使用 std C++ 线程库,然后您可以在例如获取 RAII。互斥锁,因此您的互斥锁会自动解锁,例如在异常或函数结束时。
【解决方案2】:

Sequence how I think it is

我想现在就是这样,在我发送广播信号之前,我仍然需要一种同步方式。

在那张图中,第一个 pthread_broadcast 来得太早了。

【讨论】:

    猜你喜欢
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    相关资源
    最近更新 更多