Skip to content

Commit

Permalink
解决老中医提出的不能 syncAwait 然后捕获异常的问题。测试用例见 test7
Browse files Browse the repository at this point in the history
  • Loading branch information
microcai committed Oct 21, 2024
1 parent 1e36f69 commit 6eed51d
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 2 deletions.
94 changes: 92 additions & 2 deletions include/ucoro/awaitable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,22 @@ namespace ucoro
template<concepts::awaitable_type AwaitableType>
using awaitable_return_type = template_parameter_of<AwaitableType, awaitable>;

template<typename T>
struct exception_with_result
{
using type = std::variant<std::exception_ptr, T>;
};

template<>
struct exception_with_result<void>
{
using type = std::variant<std::exception_ptr>;
};

template<typename T>
using exception_with_result_t = typename exception_with_result<T>::type;


} // namespace traits

struct debug_coro_promise
Expand Down Expand Up @@ -433,8 +449,7 @@ namespace ucoro

auto detach()
{
auto launch_coro = [](awaitable<T> lazy) -> awaitable<T> { co_return co_await std::move(lazy); };
return launch_coro(std::move(*this));
return detach(std::any{});
}

auto detach(std::any local)
Expand All @@ -452,6 +467,43 @@ namespace ucoro
return launched_coro;
}

template<typename Function>
auto detach_with_callback(Function completion_handler)
{
return detach_with_callback<Function>(std::any{}, completion_handler);
}

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>
{
using result_wrapper = ucoro::traits::exception_with_result_t<T>;
try
{
if constexpr (std::is_void_v<T>)
{
co_await std::move(lazy);
completion_handler(result_wrapper{std::current_exception()});
}
else
{
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 +515,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 +667,40 @@ auto coro_start(Awaitable&& coro)
{
return coro.detach();
}

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

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

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

template<typename T>
inline T sync_await(ucoro::awaitable<T> lazy, std::any local_)
{
ucoro::traits::exception_with_result_t<T> result;

lazy.detach_with_callback(local_, [&](ucoro::traits::exception_with_result_t<T> result_)
{
result = result_;
});

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

if (!std::is_void_v<T>)
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 6eed51d

Please sign in to comment.