gpt4 book ai didi

c++ - io_service::poll_one 非确定性行为

转载 作者:IT老高 更新时间:2023-10-28 22:59:38 25 4
gpt4 key购买 nike

在以下代码中,我希望输出始终为 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;
}

使用 boost-asio 1.60.0.6

最佳答案

观察到的行为是明确定义的并且预计会发生,但不应期望它经常发生。

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.

  • Asio 的链实现池有限。当前默认值为 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 ,然后 strand1strand2将始终使用相同的实现,从而导致 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 时会发生以下情况在原始代码中观察到:
  • strand1strand2有离散的实现
  • io_service::poll_one()执行直接发布到 strand1 的单个处理程序
  • 发布到 strand1 中的处理程序套val1
  • 处理程序发布到 strand2入队且从不调用
  • 协程创建被推迟,如 strand的调用顺序保证防止协程被创建,直到前一个处理程序发布到 strand2 之后。已执行:

    given a strand object s, if s.post(a) happens-before s.dispatch(b), where the latter is performed outside the strand, then asio_handler_invoke(a1, &a1) happens-before asio_handler_invoke(b1, &b1).


  • 另一方面,当 3观察到:
  • strand1 发生哈希冲突和 strand2 ,导致它们使用相同的底层链实现
  • io_service::poll_one()执行直接发布到 strand1 的单个处理程序
  • 发布到 strand1 中的处理程序套val1
  • 处理程序发布到 strand2入队且从不调用
  • 协程立即创建并在 boost::asio::spawn() 内调用, 设置 val3 , 如 strand2可以在保证非并发执行和处理程序调用顺序的同时安全地执行协程
  • 关于c++ - io_service::poll_one 非确定性行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38665073/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com