【问题标题】:Barrier Synchronization between 2 process using mutex使用互斥锁的2个进程之间的屏障同步
【发布时间】:2011-08-06 06:00:17
【问题描述】:

我需要使用互斥锁(仅)在 2 个线程之间实现屏障同步。屏障同步是 2 个线程在继续之前会在预定义的步骤相互等待。

我可以使用 seamaphore 来做到这一点,但是 我怎样才能只使用互斥锁来实现这一点。有人提示我需要 2 个互斥体而不是 1 个来执行此操作。

使用 Seamaphore:

#include <pthread.h>
#include <semaphore.h>
using namespace std;

sem_t s1;
sem_t s2;


void* fun1(void* i)
{
    cout << "fun1 stage 1" << endl;
    cout << "fun1 stage 2" << endl;
    cout << "fun1 stage 3" << endl;
    sem_post (&s1);
    sem_wait (&s2);
    cout << "fun1 stage 4" << endl;
}

void* fun2(void* i)
{
    cout << "fun2 stage 1" << endl;
    cout << "fun2 stage 2" << endl;
//    sleep(5);
    sem_post (&s2);
    sem_wait (&s1);
    cout << "fun2 stage 3" << endl;
}

main()
{
    sem_init(&s1, 0, 0);
    sem_init(&s2, 0, 0);
    int value; 
    sem_getvalue(&s2, &value);
    cout << "s2 = " << value << endl;

    pthread_t iThreadId;

    cout << pthread_create(&iThreadId, NULL, &fun2, NULL) << endl;
//    cout << pthread_create(&iThreadId, NULL, &fun2, NULL) << endl;
    pthread_create(&iThreadId, NULL, &fun1, NULL);
    sleep(10);
}

将上述代码编译为“g++ barrier.cc -lpthread”

【问题讨论】:

  • 为什么 fun1()fun2() 不返回 void*

标签: c++ multithreading mutex


【解决方案1】:

我不确定您是否需要两个互斥锁,一个互斥锁和一个条件变量以及一个额外的标志可能就足够了。这个想法是你通过获取互斥锁进入临界区,然后检查你是否是第一个来的线程,如果是,你等待条件。如果你是第二个来的线程,那么你唤醒等待的线程并离开。

【讨论】:

  • 我其实不想循环等待。有没有其他办法?
  • @akash-agrawai 如果您按照 David 的建议使用条件变量,则无需在循环中等待。你可以使用pthread_cond_wait
  • @David:这是明智的解决方案(并且可以扩展到更多线程),但如果只允许互斥体,那就有点作弊了。
  • @john-dibling 我不确定,有可能,我的 Google-fu 让我失望了。我很想知道。
  • @stefaanv:我支持你。这样,我们将使用某种信号量。
【解决方案2】:

NO MUTEXES 和没有锁怎么样?仅使用原子操作

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>

static sigset_t _fSigSet;
static volatile int _cMax=20, _cWait = 0;
static pthread_t    _aThread[1000];

void * thread(void *idIn)
{
int nSig, iThread, cWait, id = (int)idIn;

    printf("Start %d\n", id, cWait, _cMax);
    // do some fake weork
    nanosleep(&(struct timespec){0, 500000000}, NULL);
    // barrier
    cWait = __sync_add_and_fetch(&_cWait, 1);
    printf("Middle %d, %d/%d Waiting\n", id, cWait, _cMax);
    if (cWait < _cMax)
    {        
        // if we are not the last thread, sleep on signal
        sigwait(&_fSigSet, &nSig); // sleepytime
    }
    else
    {
        // if we are the last thread, don't sleep and wake everyone else up
        for (iThread = 0; iThread < _cMax; ++iThread)
            if (iThread != id)
                pthread_kill(_aThread[iThread], SIGUSR1);
    }

    // watch em wake up    
    cWait = __sync_add_and_fetch(&_cWait, -1);
    printf("End %d, %d/%d Active\n", id, cWait, _cMax);

    return 0;
}

int main(int argc, char** argv)
{
    pthread_attr_t attr;
    int i, err;

    sigemptyset(&_fSigSet);
    sigaddset(&_fSigSet, SIGUSR1);
    sigaddset(&_fSigSet, SIGSEGV);

    printf("Start\n");
    pthread_attr_init(&attr);
    if ((err = pthread_attr_setstacksize(&attr, 16384)) != 0)
    {
        printf("pthread_attr_setstacksize failed: err: %d %s\n", err, strerror(err));
        exit(0);
    }

    for (i = 0; i < _cMax; i++)
    {
        if ((err = pthread_create(&_aThread[i], &attr, thread, (void*)i)) != 0)
        {
            printf("pthread_create failed on thread %d, error code: %d %s\n", i, err, strerror(err));
            exit(0);
        }
    }

    for (i = 0; i < _cMax; ++i)
        pthread_join(_aThread[i], NULL);

    printf("\nDone.\n");
    return 0;
}

【讨论】:

  • 顺便说一句,像 __sync_add_and_fetch 这样的原子操作的速度只有非原子操作的 2 倍左右。此外,当我们使用互斥体/条件与 sigwait 进行试验时,您在上面看到的 sigwait 方法在睡眠和唤醒线程中的测试速度提高了 40 倍。
猜你喜欢
  • 1970-01-01
  • 2012-06-30
  • 1970-01-01
  • 1970-01-01
  • 2014-09-11
  • 2014-05-02
  • 2011-09-22
  • 1970-01-01
  • 2012-08-28
相关资源
最近更新 更多