在用C++ 11编写的分布式作业系统中,我使用以下结构实现了一个fence(即工作线程池外部的线程可能会要求阻塞,直到完成所有当前计划的作业):
struct fence
{
std::atomic<size_t> counter;
std::mutex resume_mutex;
std::condition_variable resume;
fence(size_t num_threads)
: counter(num_threads)
{}
};
Run Code Online (Sandbox Code Playgroud)
实现fence的代码如下所示:
void task_pool::fence_impl(void *arg)
{
auto f = (fence *)arg;
if (--f->counter == 0) // (1)
// we have zeroed this fence's counter, wake up everyone that waits
f->resume.notify_all(); // (2)
else
{
unique_lock<mutex> lock(f->resume_mutex);
f->resume.wait(lock); // (3)
}
}
Run Code Online (Sandbox Code Playgroud)
如果线程在一段时间内进入围栏,这种方法非常有效.然而,如果他们几乎同时尝试这样做,似乎有时会发生在原子递减(1)和开始条件var(3)的等待之间,线程产生CPU时间而另一个线程将计数器递减到零( 1)并解雇cond.var(2).这导致前一个线程在(3)中永远等待,因为它已经被通知后开始等待它.
让事情变得可行的黑客就是在(2)之前进行10毫秒的睡眠,但这显然是不可接受的.
有关如何以高效的方式解决这个问题的任何建议?
好的。此处的示例是使用 c 中的 pthread lib 提供的。
在教科书中,我遇到了以下代码:
//for thread 2
pthread_mutex_lock(&lock);
should_wake_up = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
Run Code Online (Sandbox Code Playgroud)
这段代码运行良好。我只是想知道以下代码是否也有效?
//for thread 2
pthread_mutex_lock(&lock);
should_wake_up = 1;
pthread_mutex_unlock(&lock);
pthread_cond_signal(&cond);//signal the conditional variable but the lock is not held
Run Code Online (Sandbox Code Playgroud)
以下代码的优缺点是什么?
附注。假设协作线程有代码:
//for thread 1
pthread_mutex_lock(&lock);
while(!should_wake_up)
pthread_cond_wait(&cond, &lock);
pthead_mutex_unlock(&lock);
Run Code Online (Sandbox Code Playgroud)
PS2。我遇到了其他一些问题,它指出如果我们不希望信号丢失,我们必须使用锁来确保在持有锁时不能更改关联的谓词(在这种情况下,是 should_wake_up)线程 1. 在这种情况下,这似乎不是问题。链接到帖子:[1]:在不持有锁的情况下在条件变量上发出信号。我认为他的问题是他忘记了锁定。但我的问题是不同的。