在 asio stackful 协程中直接使用 spawn 是否安全?
Is it safe to use spawn directly in an asio stackful coroutine?
当我使用 spawn 在协程中启动一个新的 stackfull 协程时,valgrind 说了很多使用未初始化的值(valgrind output)。
然后我使用 io_service.post 调用一个处理程序,并在其中启动一个新的 stackfull 协程,一切似乎都很好。
我搜索并阅读了一些文档,但找不到有关如何在 stackfull 协程中安全地创建新的 stackfull 协程的内容。
代码如下:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/system_timer.hpp>
#include <chrono>
using namespace std;
int main()
{
auto use_post = false;
boost::asio::io_service io_service;
boost::asio::spawn(io_service,
[&io_service, &use_post](boost::asio::yield_context yield){
if(use_post){
io_service.post([&io_service]{
boost::asio::spawn(io_service, [&io_service](boost::asio::yield_context yield){
boost::asio::system_timer timer(io_service);
timer.expires_from_now(std::chrono::seconds(1));
timer.async_wait(yield);
cout << "Sleep 1 second" << endl;
});
});
}
else{
boost::asio::spawn(io_service, [&io_service](boost::asio::yield_context yield){
boost::asio::system_timer timer(io_service);
timer.expires_from_now(std::chrono::seconds(1));
timer.async_wait(yield);
cout << "Sleep 1 second" << endl;
});
}
boost::asio::system_timer timer(io_service);
timer.expires_from_now(std::chrono::seconds(2));
timer.async_wait(yield);
cout << "Sleep 2 seconds" << endl;
});
io_service.run();
return 0;
}
将 use_post
变量设为 true,新的 stackfull 协程将由 post + spawn 启动。
也许我没有仔细阅读文档,我在 Boost.Asio C++ Network Programming
、N4045
和 boost asio 文档中找不到任何有用的东西。
很安全。
Boost.Asio 对 Boost.Coroutine 的第一个 class 支持是一个具有两个显着行为的薄外观:
- 协程和恢复它的处理程序使用
strand
作为它们的执行上下文。这保证协程在屈服之前不会被恢复。
- Boost.Asio 防止协程在检测到没有可用于恢复它的处理程序时无限期挂起。发生这种情况时,Boost.Asio 将销毁协程,导致挂起的堆栈展开。有关详细信息,请参阅 this 答案。
在上面的示例代码中,spawn(io_service&)
overload causes the resulting coroutine to have its own strand
. As a result, if multiple threads are running the io_service
, each of the coroutines may run in parallel, but are not guaranteed to do so. On the other hand, if one uses the spawn(yield_context)
重载,新协程将具有与调用协程相同的执行上下文(即 strand
),从而防止并行执行。
当我使用 spawn 在协程中启动一个新的 stackfull 协程时,valgrind 说了很多使用未初始化的值(valgrind output)。
然后我使用 io_service.post 调用一个处理程序,并在其中启动一个新的 stackfull 协程,一切似乎都很好。
我搜索并阅读了一些文档,但找不到有关如何在 stackfull 协程中安全地创建新的 stackfull 协程的内容。
代码如下:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/system_timer.hpp>
#include <chrono>
using namespace std;
int main()
{
auto use_post = false;
boost::asio::io_service io_service;
boost::asio::spawn(io_service,
[&io_service, &use_post](boost::asio::yield_context yield){
if(use_post){
io_service.post([&io_service]{
boost::asio::spawn(io_service, [&io_service](boost::asio::yield_context yield){
boost::asio::system_timer timer(io_service);
timer.expires_from_now(std::chrono::seconds(1));
timer.async_wait(yield);
cout << "Sleep 1 second" << endl;
});
});
}
else{
boost::asio::spawn(io_service, [&io_service](boost::asio::yield_context yield){
boost::asio::system_timer timer(io_service);
timer.expires_from_now(std::chrono::seconds(1));
timer.async_wait(yield);
cout << "Sleep 1 second" << endl;
});
}
boost::asio::system_timer timer(io_service);
timer.expires_from_now(std::chrono::seconds(2));
timer.async_wait(yield);
cout << "Sleep 2 seconds" << endl;
});
io_service.run();
return 0;
}
将 use_post
变量设为 true,新的 stackfull 协程将由 post + spawn 启动。
也许我没有仔细阅读文档,我在 Boost.Asio C++ Network Programming
、N4045
和 boost asio 文档中找不到任何有用的东西。
很安全。
Boost.Asio 对 Boost.Coroutine 的第一个 class 支持是一个具有两个显着行为的薄外观:
- 协程和恢复它的处理程序使用
strand
作为它们的执行上下文。这保证协程在屈服之前不会被恢复。 - Boost.Asio 防止协程在检测到没有可用于恢复它的处理程序时无限期挂起。发生这种情况时,Boost.Asio 将销毁协程,导致挂起的堆栈展开。有关详细信息,请参阅 this 答案。
在上面的示例代码中,spawn(io_service&)
overload causes the resulting coroutine to have its own strand
. As a result, if multiple threads are running the io_service
, each of the coroutines may run in parallel, but are not guaranteed to do so. On the other hand, if one uses the spawn(yield_context)
重载,新协程将具有与调用协程相同的执行上下文(即 strand
),从而防止并行执行。