- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我对 std::promise::set_value()
上的线程安全要求有点困惑。
Effects: Atomically stores the value r in the shared state and makes that state ready
但是,它也说 promise::set_value()
只能用于设置一次值。如果多次调用,则会抛出 std::future_error
。所以你只能设置一次 Promise 的值。
事实上,std::promise
的几乎每个教程、在线代码示例或实际用例都涉及 2 个线程之间的通信 channel ,其中一个线程调用std::future::get()
,其他线程调用std::promise::set_value()
。
我从未见过多个线程可能调用 std::promise::set_value()
的用例,即使调用了,除了一个线程之外,其他所有线程都会导致 std: :future_error
要抛出的异常。
那么为什么调用 std::promise::set_value()
的标准要求是原子的?从多个线程同时调用 std::promise::set_value()
的用例是什么?
编辑:
由于此处投票最多的答案并未真正回答我的问题,因此我认为我的问题尚不清楚。所以,澄清一下:我知道 future 和 promise 的用途以及它们是如何运作的。我的问题是,为什么标准坚持 std::promise::set_value()
必须是原子的?这是一个比“为什么在对 promise::set_value()
的调用和对 future::get()
的调用之间不能存在竞争”的更微妙的问题?
事实上,这里的许多答案(错误地)都回应说原因是因为如果 std::promise::set_value()
不是原子的,那么 std::future::get()
可能会导致竞争条件。但是这是错误的。
避免竞争条件的唯一要求是 std::promise::set_value()
必须有 happens-before与 std::future::get()
的关系——换句话说,必须保证当 std::future::wait()
返回时, std::promise::set_value()
已完成。
这与 std::promise::set_value()
本身是否是原子的完全正交。在使用条件变量的典型实现中,std::future::get()/wait()
将等待条件变量。然后,std::promise::set_value()
可以非原子地 执行任意复杂的计算来设置实际值。然后它会通知共享条件变量,(暗示具有释放语义的内存栅栏),std::future::get()
会唤醒并安全读取结果。
因此,std::promise::set_value()
本身不需要是原子的来避免这里的竞争条件 - 它只需要满足 happens-before 与std::future::get()
的关系。
所以我的问题是:为什么 C++ 标准坚持 std::promise::set_value()
实际上必须是一个原子操作,就好像一个对 std::promise::set_value()
的调用完全在互斥锁下执行?我认为没有理由存在这个要求,除非多个线程同时调用 std::promise::set_value()
有某种原因或用例。而且我想不出这样的用例,因此提出了这个问题。
最佳答案
如果不是原子存储,那么两个线程可以同时调用 promise::set_value
,它执行以下操作:
通过使这个序列原子化,第一个执行的线程 (1) 一直到 (3),任何其他同时调用 promise::set_value
的线程都将失败(1) 并使用 promise_already_satisfied
引发 future_error
。
如果没有原子性,两个线程可能会存储它们的值,然后一个会成功标记状态就绪,另一个会引发异常,即相同的结果,除了它可能是来自看到异常的线程的值。
在许多情况下,哪个线程“获胜”可能并不重要,但当它确实重要时,如果没有原子性保证,您将需要在 promise::set_value
调用周围包装另一个互斥锁。比较和交换等其他方法不起作用,因为您无法检查 future (除非它是 shared_future
)来查看您的值(value)是否赢了。
当哪个线程“获胜”无关紧要时,您可以给每个线程自己的 future ,并使用 std::experimental::when_any
收集碰巧可用的第一个结果。
经过一些历史研究后编辑:
虽然上述(两个线程使用同一个 promise 对象)看起来不是一个好的用例,但它肯定是由当代论文之一将 future
引入 C++ : N2744 .本文提出了几个用例,它们有这样的冲突线程调用 set_value
,我将在这里引用它们:
Second, consider use cases where two or more asynchronous operations are performed in parallel and "compete" to satisfy the promise. Some examples include:
- A sequence of network operations (e.g. request a web page) is performed in conjunction with a wait on a timer.
- A value may be retrieved from multiple servers. For redundancy, all servers are tried but only the first value obtained is needed.
In both examples, the first asynchronous operation to complete is the one that satisfies the promise. Since either operation may complete second, the code for both must be written to expect that calls to
set_value()
may fail.
关于c++ - std::promise set_value 和线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45626919/
我正在开发一个小型图书馆,我需要做的一件事是让访问者访问一些数据并返回结果。 在一些较旧的 C++ 代码中,访问者需要声明一个 typedef return_type .例如,boost::stati
我正在尝试使用std:map类型的键和值制作std::any Visual Studio 2017 std::map m("lastname", "Ivanov"); std::cout (m["la
我已经在 C++ 的 map 中声明了一个集合为 std::map> .如何循环访问或打印设定值? 最佳答案 如果你知道如何迭代 std::map或 std::set单独地,您应该可以毫无问题地组合迭
如何循环? 我已经试过了: //----- code std::vector >::iterator it; for ( it = users.begin(); it != users.end();
我有两个用例。 A.我想同步访问两个线程的队列。 B.我想同步两个线程对队列的访问并使用条件变量,因为其中一个线程将等待另一个线程将内容存储到队列中。 对于用例 A,我看到了使用 std::lock_
我正在查看这两种类型特征的文档,但不确定有什么区别。我不是语言律师,但据我所知,它们都适用于“memcpy-able”类型。 它们可以互换使用吗? 最佳答案 不,这些术语不能互换使用。这两个术语都表示
我有以下测试代码,其中有一个参数 fS,它是 ofstream 的容器: #include #include #include #include int
这是这个问题的延续 c++ function ptr in unorderer_map, compile time error 我试图使用 std::function 而不是函数指针,并且只有当函数是
std::unordered_map str_bool_map = { {"a", true}, {"b", false}, {"c", true} }; 我们可以在此映射上使
我有以下对象 std::vector> vectorList; 然后我添加到这个使用 std::vector vec_tmp; vec_tmp.push_back(strDRG); vec_tmp.p
为什么 std::initializer_list不支持std::get<> , std::tuple_size和 std::tuple_element ?在constexpr中用得很多现在的表达式,
我有一个像这样定义的变量 auto drum = std::make_tuple ( std::make_tuple ( 0.3f , Ex
假设我有一个私有(private)std::map在我的类(class)里std::map 。我怎样才能将其转换为std::map返回给用户?我想要下面的原型(prototype) const std
假设我有一个私有(private)std::map在我的类(class)里std::map 。我怎样才能将其转换为std::map返回给用户?我想要下面的原型(prototype) const std
问题 我正在尝试将 lambda 闭包传递给 std::thread,它使用任意封闭参数调用任意封闭函数。 template std::thread timed_thread(Function&& f
我想创建一个模板类,可以容纳容器和容器的任意组合。例如,std::vector或 std::map ,例如。 我尝试了很多组合,但我必须承认模板的复杂性让我不知所措。我编译的关闭是这样的: templ
我有一个 std::vector>我将其分配给相同类型的第二个 vector 。 我收到这个编译器错误: /opt/gcc-8.2.0/include/c++/8.2.0/bits/stl_algob
有时候,我们有一个工厂可以生成一个 std::unique_ptr vector ,后来我们想在类/线程/你命名的之间共享这些指针。因此,最好改用 std::shared_ptr 。当然有一种方法可以
这个问题在这里已经有了答案: Sorting a vector of custom objects (14 个答案) 关闭 6 年前。 我创建了一个 vector vector ,我想根据我定义的参
我有三个类(class)成员: public: std::vector > getObjects(); std::vector > getObjects() const; privat
我是一名优秀的程序员,十分优秀!