如何序列化异步pthreads代码段

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何序列化异步pthreads代码段相关的知识,希望对你有一定的参考价值。

我有许多需要临时访问共享资源的抢先(异步)线程(TA)。这将是pthread_mutex的典型用途。

但是,我有一些事情使这更复杂:

  • 我几乎无法控制整个代码,因为我只提供了一组函数来简化程序。
  • 有一组“主”线程(TM),我几乎无法控制,并使用私有互斥锁来访问所述共享资源。他们使用管理这些线程的私有调度程序,这样只允许一个人在任何时间运行,有效地让这些线程协同运行。
  • 任何这些主线程(TM)都可能导致异步线程(TA)运行。这是我想要提供额外功能的程序员代码的所有部分。

我必须等待那些TM线程处于“安全”状态,然后我可以允许TA线程访问共享资源。我有办法做到这一点。

因此,想法是暂停(阻止)所有TA线程,直到在任何一个TM线程中达到安全状态,然后暂停该TM线程,允许每个TA线程一个接一个地运行,并恢复TM线程一旦完成它们。

当TM线程达到所述安全状态时,将调用我的函数shared_resource_is_safe()

此外,程序员必须在访问共享资源之前和之后调用我的函数acquire_access()surrender_access()

所以我有三个功能要实现,我正在努力使用互斥锁和/或信号量来实现我的目标。

这是我到目前为止所提出的:

dispatch_semaphore_t semaphore;
pthread_mutex_t mutex;
int is_safe = 0;

void setup_once() {
    semaphore = dispatch_semaphore_create (0);
    pthread_mutex_init (&mutex, NULL);
}

void acquire_access() {
    pthread_mutex_lock (&mutex);
    dispatch_semaphore_wait (semaphore, DISPATCH_TIME_FOREVER);
    assert(is_safe);
}

void surrender_access() {
    pthread_mutex_unlock (&mutex);
}

void shared_resource_is_safe() {
    // this shall resume thread that's called acquire_access()
    is_safe = 1;
    while (dispatch_semaphore_signal (semaphore) != 0) {
        // Wait until the signaled thread
        // has called surrender_access()
        pthread_mutex_lock (&mutex);
        pthread_mutex_unlock (&mutex);
    }
    is_safe = 0;
}

信号量用于任何线程调用acquire_access()等待shared_resource_is_safe()

互斥锁应确保每个异步线程都等待shared_resource_is_safe()允许它运行。

但这并不能可靠地工作。我遇到了is_safe的断言在异步线程中失败的情况,这意味着主线程不会等待异步线程调用surrender_access()。我做错了什么?

答案

mevets的答案可以识别你的错误。如上所述,您可以使用条件变量来解决此问题:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_safe = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond_waiters = PTHREAD_COND_INITIALIZER;
int is_safe = 0;
long waiters = 0;

void acquire_access(void)
{   
    pthread_mutex_lock(&mutex);
    waiters++;
    while (!is_safe)
        pthread_cond_wait(&cond_safe, &mutex);
}

void surrender_access(void)
{   
    waiters--;
    if (!waiters)
        pthread_cond_signal(&cond_waiters);
    pthread_mutex_unlock(&mutex);
}

void shared_resource_is_safe(void)
{   
    pthread_mutex_lock(&mutex);
    if (waiters)
    {
        is_safe = 1;
        pthread_cond_broadcast(&cond_safe);
        while (waiters)
            pthread_cond_wait(&cond_waiters, &mutex);
        is_safe = 0;
    }
    pthread_mutex_unlock(&mutex);
}
另一答案

当dispatch_semaphore_signal()返回0(表示没有人等待它)时,它增加了信号量,因此下一个dispatch_semaphore_wait()将获取信号量而不等待。

你想要的是一个条件变量,调度不提供。可以使用信号量构造一个[即。保持一个单独的计数器,表示有多少人被互斥锁保护起来,但是在这一点上,你可能想要考虑一下你是不是要挖一个更深的洞。

Dispatch的设计考虑了特定的模型,你似乎正在努力颠覆它。有没有办法以另一种方式获得你想要的效果?

以上是关于如何序列化异步pthreads代码段的主要内容,如果未能解决你的问题,请参考以下文章

如何理解这段代码片段中的两对括号?

Spark闭包与序列化

如何在 Swift 上使这段代码异步

Asp.Net Core 轻松学-经常使用异步的你,可能需要看看这个文章

NodeJs异步的执行过程

VS2015 代码片段整理