cppreference有一个co_await的例子,它在另一个线程上恢复协程。
但是在没有同步的情况下这样做安全吗?
具体来说,resume_on_new_thread()从一个线程开始,然后在co_await之后用另一个线程访问相同的协程“帧”继续。通常,如果你从两个线程访问相同的数据,你需要同步。
#include <coroutine>
#include <iostream>
#include <stdexcept>
#include <thread>
auto switch_to_new_thread(std::jthread& out)
{
struct awaitable
{
std::jthread* p_out;
bool await_ready() { return false; }
void await_suspend(std::coroutine_handle<> h)
{
std::jthread& out = *p_out;
if (out.joinable())
throw std::runtime_error("Output jthread parameter not empty");
out = std::jthread([h] { h.resume(); });
// Potential undefined behavior: accessing potentially destroyed *this
// std::cout << "New thread ID: " << p_out->get_id() << '\n';
std::cout << "New thread ID: " << out.get_id() << '\n'; // this is OK
}
void await_resume() {}
};
return awaitable{&out};
}
struct task
{
struct promise_type
{
task get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
};
task resuming_on_new_thread(std::jthread& out)
{
std::cout << "Coroutine started on thread: " << std::this_thread::get_id() << '\n';
co_await switch_to_new_thread(out);
// awaiter destroyed here
std::cout << "Coroutine resumed on thread: " << std::this_thread::get_id() << '\n';
}
int main()
{
std::jthread out;
resuming_on_new_thread(out);
}
考虑函数是否有数据:
task resuming_on_new_thread(std::jthread& out)
{
int data = 0; // Store some data using thread A.
std::cout << "Coroutine started on thread: " << std::this_thread::get_id() << '\n';
co_await switch_to_new_thread(out);
// awaiter destroyed here
std::cout << "Coroutine resumed on thread: " << std::this_thread::get_id() << '\n';
std::cout << data << '\n'; // Access data with thread B. **Is this safe?**
}
2条答案
按热度按时间ldfqzlk81#
是的,它是安全的。
std::jthread
的构造函数是synchronization。r1zk6ea12#
这是安全的。请记住,当协程挂起时,它会将控制权返回给调用者。因此,只有恢复协程的线程才能继续执行协程主体。在您的示例中,协程从主线程开始,然后挂起,然后在
out
上恢复。只有当您尝试从 *2个不同的 * 线程恢复 * 相同的 * 协程时,才会发生数据争用,这是未定义的行为,如
std::coroutine_handle<Promise>::resume()
here的注解中所述如果
*this
不引用挂起的协程[...],则该行为未定义。并发恢复协程可能导致数据争用。