我有许多抢先(异步)线程(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()
。我该怎么办?
答案 0 :(得分:2)
当dispatch_semaphore_signal()返回0(表示没有人在等待它)时,它会增加信号量,因此下一个dispatch_semaphore_wait()将获得信号量而无需等待。
您想要的是条件变量,而调度没有提供。可以使用信号量来构造一个。单独保存 有多少可以通过互斥锁唤醒],但是此时,您可能要考虑是否没有在挖一个更深的洞。
分派在设计时就考虑了特定的模型,您似乎正在努力颠覆这一点。也许可以通过另一种方式来获得想要的效果?
答案 1 :(得分:1)
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);
}