根据cppreference,std::atomic::notify\u one()将通知至少一个等待所述atomic的线程。这意味着根据标准,它可以解锁多个线程。这与std::condition\u variable::notify\u one()相反,后者指定它将解锁(不超过)一个线程。
这种差异来自哪里?这不是使用相同的底层机制吗?就标准库的实现而言,是否所有流行的都有机会通过此调用实际解除屏蔽多个,还是有一些总是完全解除屏蔽一个?
据我所知,他们可以使用相同的机制,但不必如此。我通常使用的实现是libstdc,它的atomic::notify_one()绝对不同。
condition\u变量相当不透明,在bits/std\u互斥体中实现为\uu condvar。h收割台。其notify\u one()只调用pthread包装器:
void
notify_one() noexcept
{
int __e __attribute__((__unused__)) = __gthread_cond_signal(&_M_cond);
__glibcxx_assert(__e == 0);
}
而notify_all()则调用__gthread_cond_broadcast。
这与原子相比,原子涉及的内容更多,但最终使用一系列函数通知线程,从\uu原子\u notify\u地址开始:
template<typename _Tp>
void
__atomic_notify_address(const _Tp* __addr, bool __all) noexcept
{
__detail::__bare_wait __w(__addr);
__w._M_notify(__all);
}
__waiter_base::_M_notify:
void
_M_notify(bool __all, bool __bare = false)
{
if (_M_laundered())
{
__atomic_fetch_add(_M_addr, 1, __ATOMIC_SEQ_CST);
__all = true;
}
_M_w._M_notify(_M_addr, __all, __bare);
}
__服务员\u池\u基::\u M\u通知:
void
_M_notify(const __platform_wait_t* __addr, bool __all, bool __bare) noexcept
{
if (!(__bare || _M_waiting()))
return;
#ifdef _GLIBCXX_HAVE_PLATFORM_WAIT
__platform_notify(__addr, __all);
#else
if (__all)
_M_cv.notify_all();
else
_M_cv.notify_one();
#endif
}
因此,如果没有\u GLIBCXX\u HAVE\u PLATFORM\u WAIT,libstdc将只使用条件变量通知一个或所有线程。否则,它将使用futex实现,并且可能会唤醒(多达?)INT\u MAX threads,请参阅\uu platform\u notify:
template<typename _Tp>
void
__platform_notify(const _Tp* __addr, bool __all) noexcept
{
syscall (SYS_futex, static_cast<const void*>(__addr),
static_cast<int>(__futex_wait_flags::__wake_private),
__all ? INT_MAX : 1);
}
std::atomic::etc
和std::condition_variable::都可以在任何时候解除屏蔽,包括在调用
notify_one
的特定时间。
所以在规范方面,虽然看起来确实标准对两者使用了不同的措辞([atomics.types.operation]/32中的“至少一个”而在[thread.condition.condvar]/5中只是“一个”),但我不认为这里有任何规范性差异。实现可以在调用
notify_one
时自由解除屏蔽两个等待操作的任意数量的线程,只要它至少是一个(如果有的话正在等待)。对于std::atomic::notify_one
以及std::condition_variable::notify_one
(即“(不超过)”是错误的)都是如此。
在
st tomic
等待操作的提案[P1135R4]的早期修订中,它在提议的措辞中仍然说“一个”而不是“至少一个”。
这一点随着修订[P1135R5]而改变,根据修订[P1135R5],措辞改进部分是为了响应LWG电话会议的反馈。我认为这些电话会议没有任何留档是公开的,所以我不知道这种措辞变化是否有具体意图。
也许它是为了避免误解,因为虚假的解除屏蔽在不同的段落中被提及,或者它可能是为了传达有一些实现可以解除屏蔽多个/所有等待操作,这些操作专门打算被支持。另请参阅问题和本答案下的评论。
angular-atomic-notify 是显示消息的 Angular 模块。 demo: Online demo
我有一个用于读写器的环形缓冲区。我跟踪环形缓冲区中的数字if条目,不允许覆盖尚未读取的条目。我使用std::condition\u variable wait()和notify\u one()来同步读写器。读卡器的基本条件是 这一切似乎都奏效了,但有一件事我不明白。当读写器调用notify\u one()时,不会导致上下文切换。我读过并理解它是这样工作的。然而,在写入程序写入一个条目以填充缓冲区的
我读过C 11内存模型中的并发性:原子性和易失性以及std::memory\u order\u seq\u cst的工作原理,它没有多大帮助,直接回答了我的问题。 来自https://en.cppreference.com/w/cpp/thread/condition_variable/notify_one: notify one()和wait for()的三个原子部分(解锁等待、唤醒和锁定)的效
在Flink中,像“平面地图”、“地图”等运算符称为任务,如果我将平面地图的并行度设置为30,那么这个任务有30个子任务。 现在,如果我只有一个插槽,它会在一个插槽中产生多个线程吗?还是每个插槽只有一个线程? Flink会在该插槽中简单地创建30个线程,还是使用类似线程池的东西? 以上不是一个恰当的例子。 假设在作业中我有操作符flatMap和map,它们都有并行度1,我只有一个插槽,这个插槽会创
我试着编译简单的代码 对于Clang++3.2(从llvm.org下载为LLVM3.2;在mac OS.x 10.8.3上,此操作失败,出现错误 当我使用/usr/bin/clang++时(这是OS或Xcode附带的),它编译得很好。在这两种情况下,libc++都是/usr/lib/c++/v1。 我错过了什么?LLVM3.2附带了另一个libc++吗?(我在Clang3.2树中找不到任何东西)。
考虑以下示例代码,其中线程A在队列上推送函数,线程B在从队列中弹出时执行这些函数: 其中是一个并发队列,它有一个和一个函数,每个返回一个指示给定操作是否成功。因此,如果已满,则返回,如果为空,则返回。 现在我想知道代码是否在所有情况下都是线程安全的。让我们假设线程B的失败并即将调用