这是Can C++ 11的后续条件condition_variables用于同步进程?.
std :: condition_variable对象可以用作计数信号量吗?
Methinks不是因为对象似乎绑定到std :: mutex,这意味着它只能用作二进制信号量.我在网上看过,包括这里,这里和这里,但是找不到使用这些对象作为计数信号量的参考或示例.
我一直在仔细研究以下SO问题的接受答案:C++ 0x没有信号量?如何同步线程?
在该答案的信号量实现中,这里是wait()函数的实现:
void wait()
{
boost::mutex::scoped_lock lock(mutex_);
while(!count_)
condition_.wait(lock);
--count_;
}
Run Code Online (Sandbox Code Playgroud)
我试图了解while(!count_)病情的目的.
另一个SO问题的答案(信号量的这种实现如何工作?)表明当notify_one()条件变量被调用时,有可能超过一个等待该条件变量的线程将被唤醒 - 因此需要while环.我想确认一下 - 是完整的和/或正确的答案,还是有其他原因while需要循环?
如果多个线程被唤醒,哪个线程拥有互斥锁?我想的越多,如果多个线程因单次调用而唤醒,那么看起来就越不明确notify_one().BOTH唤醒线程是否不可能将count_值看作高于0,并继续递减count_,导致count_值小于0,并且失败信号量的目的(和正确性)?
我使用std::atomics类似于 Herb Sutters CPPCon2014演讲的方式实现了一个无锁的单生产者多消费者队列。
有时,生产者太慢而无法满足所有消费者的需求,因此消费者可能会饿死。我想防止饥饿的消费者加入队列,因此我为10ms. 这个值是任意的,不是最优的。我想使用一个信号,一旦队列中再次有空闲插槽,消费者就可以将其发送给生产者。在基于锁的实现中,我自然会使用std::condition_variable此任务。但是现在在我的无锁实现中我不确定,如果引入 a 是正确的设计选择mutex,只是为了能够使用std::condition_variable。
我只是想问你,如果 mutex在这种情况下是否是正确的方法?
编辑:我有一个从不睡觉的制作人。并且有多个消费者,如果他们饿了就去睡觉。因此整个系统一直在进步,因此我认为它是无锁的。我当前的解决方案是在消费者 GetData 函数中执行此操作:
std::unique_lock<std::mutex> lk(_idleMutex);
_readSetAvailableCV.wait(lk);
一旦新数据准备好,这在生产者线程中:
_readSetAvailableCV.notify_all();
前言:我在这里看到过类似的问题,但其中没有一个似乎回答了我的问题.
是否有一种可靠的方法可以确保在第一次从生产者线程调用notify_one()之前调用消费者线程中的wait()方法?
即使在消费者线程中使用unique_lock,生产者线程也有可能首先运行,锁定互斥锁并在消费者调用wait()之前调用notify(),因此,我的应用程序将首先缺少notify()调用
编辑:谢谢你的所有答案,他们确实帮助了我.我的问题是这个消费者循环中的第一个wait-notify():
while (!timeToQuit) {
gdcv.wait(gdcondlock);
gdlock.lock();
//spurious wakeup
if (gdQueue.empty()) {
gdlock.unlock();
continue;
}
//some work here
gdlock.unlock();
}
Run Code Online (Sandbox Code Playgroud)
我想,我将不得不为第一次循环迭代编写额外的代码.
EDIT2:这个循环和第二个锁(unique_lock btw)存在,因为有多个生产者和消费者访问队列.
EDIT3:boost::lockfree::queue在任何人有类似问题的情况下,借助于等待此特定线程的正确方法:
nfq_data* data;
while (!timeToQuit) {
gdcv.wait(gdlock,[&]{return !gdQueue.empty() || timeToQuit;});
gdQueue.pop(data);
gdlock.unlock();
}
Run Code Online (Sandbox Code Playgroud) 我已经将 pthreads 用于并发程序,主要使用自旋锁、互斥锁和条件变量。
我开始研究使用 std::thread 和 std::mutex 的多线程,我注意到 pthread 中似乎没有与自旋锁等效的东西。
有谁知道这是为什么?
示例代码int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);用作CLOCK_REALTIME时间源,clock_gettime(struct timespec *timeout) 但这很容易受到系统时钟时间更改的影响,例如某些其他进程会向后更改时间。
是否支持sem_timedwait支持CLOCK_MONOTONIC时间源
下面是一些示例代码供参考。
struct timespec ts;
sem_t sema;
sem_init(&sema, 0, 0)
int ret;
if ( -1 != (ret = clock_gettime(CLOCK_REALTIME, &ts))){
ts.tv_sec += 1;
return sem_timedwait(sema, &ts);
}
Run Code Online (Sandbox Code Playgroud) 编辑:这不是任何允许在 post() 中互斥锁定的问题的重复。请仔细阅读,我需要一个无锁帖子()!如果您没有真正的答案,请不要标记此重复项。
信号量(如在 Linux 中)是一个有用的构建块,但在 C++ 标准中没有找到,在 boost(目前)中也没有。我主要讨论的是抢占式调度程序中单个进程的线程之间的信号量。
我对它们的非阻塞(即无锁)特别感兴趣,除非它实际上需要阻塞。也就是说,post() 和 try_wait() 应该始终是无锁的。如果 wait() 调用强烈发生在足够的 post() 返回之后,那么 wait() 调用应该是无锁的。此外,阻塞 wait() 应该被调度程序阻塞而不是自旋锁定。如果我还想要一个带有超时的 wait_for 该怎么办 - 它会使实现进一步复杂化,同时仍然避免饥饿?
信号量不在标准中是否有原因?
Edit3:所以,我不知道有一个针对标准 P0514R4 的提案可以准确处理这些问题,并且除了专门添加 std::semaphore 之外,还可以解决此处提出的所有问题。http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0514r4.pdf
而且boost没有这些。具体来说,进程间的进程是自旋锁定的。
哪些库支持类似的东西?
是否可以通过 windows api 和其他广泛的系统来实现它?
编辑:不可能使用原子+互斥体+条件变量来实现无锁 - 您要么必须在发布中阻塞,要么在等待中旋转。如果您想要无锁的 post(),则不能在 post() 中锁定互斥体。我想在可能抢占式的调度程序上运行,并且我不希望 post() 被其他获取互斥锁并被抢占的线程阻塞。那么,这不是像C++0x has no semaphores 这样的问题的重复吗?如何同步线程?
edit2:下面的示例实现只是为了演示使用atomics+mutex+condvar可以完成的最佳操作,据我所知。post() 和 wait() 执行一次无锁比较交换,并且只有在必须时,它们才会锁定互斥锁。
然而 post() 不是无锁的。更糟糕的是,它可能会被锁定互斥锁并被抢占的 wait() 阻塞。
为了简单起见,我只实现了 post_one() 和 wait_one_for(Duration),而不是 post(int) 和 wait_for(int,Duration)。另外,我假设标准没有承诺无虚假唤醒。
class semaphore //provides acquire release memory ordering for the …Run Code Online (Sandbox Code Playgroud) 我有一个方法,它在另一个线程上执行,然后在主线程上执行。如果完成,它会调用回调。但主线程必须等待,否则它会销毁回调想要返回的对象。
现在,为了简单起见,我有以下代码:
int main()
{
Something* s = new Something();
s.DoStuff(); // Executed on another thread
delete (s); // Has to wait for DoStuffCallback() to be executed
}
void Something::DoStuff()
{
// Does stuff
// If done, calls its callback
}
void Something::DoStuffCallback()
{
// DoStuff has finished work
}
Run Code Online (Sandbox Code Playgroud)
我怎样才能等到 DoStuffCallback() 执行然后继续主线程?
多谢!
编辑:
这对我不起作用,因为我无法访问正确的编译器。(我已经提到VS2010)