Skip to content

Commit

Permalink
解决老中医提出的不能 syncAwait 然后捕获异常的问题。测试用例见 test7
Browse files Browse the repository at this point in the history
  • Loading branch information
microcai committed Oct 20, 2024
1 parent 1e36f69 commit d4be395
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 0 deletions.
108 changes: 108 additions & 0 deletions include/ucoro/awaitable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,79 @@ namespace ucoro
return launched_coro;
}

template<typename Function>
auto detach_with_callback(Function completion_handler)
{
auto launched_coro = [](awaitable<T> lazy, auto completion_handler) mutable -> awaitable<void>
{
if constexpr (std::is_void_v<T>)
{
using result_wrapper = std::variant<std::exception_ptr>;
try
{
co_await std::move(lazy);
completion_handler(result_wrapper{std::current_exception()});
}catch(...)
{
completion_handler(result_wrapper{std::current_exception()});
}
}
else
{
using result_wrapper = std::variant<std::exception_ptr, T>;
try
{
completion_handler(result_wrapper{co_await std::move(lazy)});
}
catch(...)
{
completion_handler(result_wrapper{std::current_exception()});
}
}

}(std::move(*this), std::move(completion_handler));

return launched_coro;
}

template<typename Function>
auto detach_with_callback(std::any local, Function completion_handler)
{
auto launched_coro = [](awaitable<T> lazy, auto completion_handler) mutable -> awaitable<void>
{
if constexpr (std::is_void_v<T>)
{
using result_wrapper = std::variant<std::exception_ptr>;
try{
co_await std::move(lazy);
completion_handler(result_wrapper{std::current_exception()});
}catch(...)
{
completion_handler(result_wrapper{std::current_exception()});
}
}
else
{
using result_wrapper = std::variant<std::exception_ptr, T>;
try
{
completion_handler(result_wrapper{co_await std::move(lazy)});
}
catch(...)
{
completion_handler(result_wrapper{std::current_exception()});
}
}
}(std::move(*this), std::move(completion_handler));

if (local.has_value())
{
launched_coro.set_local(local);
}

return launched_coro;
}

std::coroutine_handle<promise_type> current_coro_handle_;
};

Expand All @@ -463,6 +536,7 @@ namespace ucoro
auto result = awaitable<T>{std::coroutine_handle<awaitable_promise<T>>::from_promise(*this)};
return result;
}

} // namespace ucoro

//////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -614,3 +688,37 @@ auto coro_start(Awaitable&& coro)
{
return coro.detach();
}

template<typename T>
inline T sync_await(ucoro::awaitable<T> lazy)
{
std::variant<std::exception_ptr, T> result;
lazy.detach_with_callback([&](std::variant<std::exception_ptr, T> result_)
{
result = result_;
});

if (std::holds_alternative<std::exception_ptr>(result))
{
std::rethrow_exception(std::get<std::exception_ptr>(result));
}

return std::get<T>(result);
}

template<typename T>
inline T sync_await(ucoro::awaitable<T> lazy, std::any local_)
{
std::variant<std::exception_ptr, T> result;
lazy.detach_with_callback(local_, [&](std::variant<std::exception_ptr, T> result_)
{
result = result_;
});

if (std::holds_alternative<std::exception_ptr>(result))
{
std::rethrow_exception(std::get<std::exception_ptr>(result));
}

return std::get<T>(result);
}
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ set_target_properties(ucoro_tests PROPERTIES FOLDER "ucoro_tests")

add_subdirectory(test1)
add_subdirectory(test2)
add_subdirectory(test7)

find_package(Boost 1.60 COMPONENTS thread system atomic)
if(Boost_FOUND)
Expand Down
6 changes: 6 additions & 0 deletions tests/test7/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

add_executable(test7 test.cpp)
target_link_libraries(test7 ucoro)

add_test(NAME test7 COMMAND test7)
set_target_properties(test7 PROPERTIES FOLDER "ucoro_tests")
29 changes: 29 additions & 0 deletions tests/test7/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

#include "ucoro/awaitable.hpp"
#include <iostream>

ucoro::awaitable<int> test()
{
throw std::runtime_error("test throw");
co_return 1;
}

ucoro::awaitable<int> coro_compute()
{
co_return co_await test();
}

int main(int argc, char** argv)
{
try
{
std::string str = "hello";
sync_await(coro_compute(), str);
}
catch (std::exception& e)
{
std::cerr << "抓到异常" << e.what() << std::endl;
}

return 0;
}

0 comments on commit d4be395

Please sign in to comment.