- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
在以下代码中,我希望输出始终为 1,因为我希望在 poll_one()
时只运行一个处理程序被称为。然而,大约 300 次,输出实际上是 3。根据我对 boost 库的理解,这似乎是不正确的。非确定性行为是错误还是预期?
#include <boost/asio.hpp>
int main() {
boost::asio::io_service io;
boost::asio::io_service::work io_work(io);
boost::asio::io_service::strand strand1(io);
boost::asio::io_service::strand strand2(io);
int val = 0;
strand1.post([&val, &strand2]() {
val = 1;
strand2.post([&val]() {
val = 2;
});
boost::asio::spawn(strand2, [&val](boost::asio::yield_context yield) {
val = 3;
});
});
io.poll_one();
std::cout << "Last executed: " << val << std::endl;
return 0;
}
最佳答案
观察到的行为是明确定义的并且预计会发生,但不应期望它经常发生。
Asio 的链实现池有限,链的默认分配策略是散列。如果发生哈希冲突,两条链将使用相同的实现。当发生哈希冲突时,示例简化为以下 demo :
#include <cassert>
#include <boost/asio.hpp>
int main()
{
boost::asio::io_service io_service;
boost::asio::io_service::strand strand1(io_service);
// Have strand2 use the same implementation as strand1.
boost::asio::io_service::strand strand2(strand1);
int value = 0;
auto handler1 = [&value, &strand1, &strand2]() {
assert(strand1.running_in_this_thread());
assert(strand2.running_in_this_thread());
value = 1;
// handler2 is queued into strand and never invoked.
auto handler2 = [&value]() { assert(false); };
strand2.post(handler2);
// handler3 is immediately executed.
auto handler3 = [&value]() { value = 3; };
strand2.dispatch(handler3);
assert(value == 3);
};
// Enqueue handler1.
strand1.post(handler1);
// Run the event processing loop, executing handler1.
assert(io_service.poll_one() == 1);
}
io_service.poll_one()
执行单个就绪处理程序 ( handler1
) handler2
永远不会被调用 handler3
在 strand2.dispatch()
内立即调用, 如 strand2.dispatch()
从处理程序中调用,其中 strand2.running_in_this_thread()
返回 true
io_service::poll_one()
将运行 io_service
的事件循环并且没有阻塞,它最多会执行一个准备运行的处理程序。处理程序在 dispatch()
的上下文中立即执行永远不会进入 io_service
,并且不受 poll_one()
的约束调用单个处理程序的限制。 boost::asio::spawn(strand, function)
重载启动一个堆栈式协程,就像 strand.dispatch()
:strand.running_in_this_thread()
返回 false
对于调用者,则协程将被发布到 strand
用于延迟调用 strand.running_in_this_thread()
返回 true
对于调用者,则协程将立即执行 strand
使用相同实现的对象仍然保持链的保证。即不会发生并发执行和order of handler invocation定义明确。离散时strand
对象使用离散实现,并且多个线程正在运行 io_service
,然后可以观察到并发执行的离散链。然而,当离散strand
对象使用相同的实现,即使多个线程正在运行,也不会观察到并发io_service
.这种行为是 documented :The implementation makes no guarantee that handlers posted or dispatched through different strand objects will be invoked concurrently.
193
并且可以通过定义BOOST_ASIO_STRAND_IMPLEMENTATIONS
来控制到所需的数量。此功能在 Boost.Asio 1.48 release notes 中有所说明。Made the number of strand implementations configurable by defining
BOOST_ASIO_STRAND_IMPLEMENTATIONS
to the desired number.
1
,然后 strand1
和 strand2
将始终使用相同的实现,从而导致 val
永远3
( demo )。 strand
使用相同的实现。对象。通过定义 BOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION
,可以将分配策略改为循环,防止冲突发生,直到BOOST_ASIO_STRAND_IMPLEMENTATIONS + 1
链分配已经发生。此功能在 Boost.Asio 1.48 发行说明中有所说明:Added support for a new
BOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION
flag which switches the allocation of strand implementations to use a round-robin approach rather than hashing.
1
时会发生以下情况在原始代码中观察到:
strand1
和 strand2
有离散的实现 io_service::poll_one()
执行直接发布到 strand1
的单个处理程序strand1
中的处理程序套val
至 1
strand2
入队且从不调用 strand
的调用顺序保证防止协程被创建,直到前一个处理程序发布到 strand2
之后。已执行:given a strand object
s
, ifs.post(a)
happens-befores.dispatch(b)
, where the latter is performed outside the strand, thenasio_handler_invoke(a1, &a1)
happens-beforeasio_handler_invoke(b1, &b1)
.
3
观察到:
strand1
发生哈希冲突和 strand2
,导致它们使用相同的底层链实现 io_service::poll_one()
执行直接发布到 strand1
的单个处理程序strand1
中的处理程序套val
至 1
strand2
入队且从不调用 boost::asio::spawn()
内调用, 设置 val
至 3
, 如 strand2
可以在保证非并发执行和处理程序调用顺序的同时安全地执行协程关于c++ - io_service::poll_one 非确定性行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38665073/
在以下代码中,我希望输出始终为 1,因为我希望在 poll_one() 时只运行一个处理程序被称为。然而,大约 300 次,输出实际上是 3。根据我对 boost 库的理解,这似乎是不正确的。非确定性
io_service::poll_one Run the io_service object's event processing loop to execute one ready handler.
我在 Qt Quick 应用程序中使用 asio(仅独立 header )。 如果我理解正确的话,Qt 和 asio 都有自己的事件循环,我使用 QTimer 信号来调用包含我的 asio::io_s
以嵌套或递归方式(即从处理程序内)调用 asio::io_service::poll() 或 poll_one() 是否有效? 一个真正基本的测试似乎暗示这是有效的(我只在一个平台上完成了测试)但我想
我是一名优秀的程序员,十分优秀!