[C++] C++20: ์ฝ๋ฃจํด
์ฝ๋ฃจํด์ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํด ๋์ ๋ ์ ๊ธฐ๋ฅ์ด๋ค.
๋ค๋ฅธ ์ธ์ด๋ค์์ ์ฌ์ฉํ๋ ์ฝ๋ฃจํด๊ณผ ๋น๊ตํ๋ฉด ์ ํ์ค๊ฐ ์๋นํ ๋ณต์กํ ๊ฒ ๊ฐ๋ค.
์ฐธ์ผ๋ก C++๋ต๋ค๊ณ ํ ์ ์๋ค.
ํ์ ์ ์
๋จผ์ ์ฝ๋ฃจํด์ ์ฌ์ฉํ ์ฝ๋ฃจํด์ฉ ํ์ ์ ์ ์ํ๋ค.
์ฝ๋ฃจํด ํ์
์ ๋ฌธ๋ฒ์ ๋ฐ๋ฅด๋ฉด promise๋ผ๋ ๋ด๋ถ ํ์
์ ๊ฐ์ ธ์ผ ํ๋ค.
์์ํ ์ธ๋ถ์ฌํญ์ ๋ค ์ฒ๋ฆฌํ๊ณ ์ถ์ง ์๋ค๋ฉด coroutine_handler๋ผ๋ ๋
์์ ์์๋ฐ์๋ ์ข๋ค.
๊ทธ๋ผ ์ด๋ฐ ์์ผ๋ก ๋๋ค.
ํ๋ก๋ฏธ์ค ํ์
์ ๊ท๊ฒฉ์ ๋ํด์๋ ๋ฐ๋ก ๋ค์ ๋ฌธ๋จ์์ ๋ค๋ฃฌ๋ค.
ํ๋ก๋ฏธ์ค ์ ์
์ด๊ฒ ์ข ๋ณต์กํ๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ด 4๊ฐ์ง์ ๋ฉ์๋๋ฅผ ๊ตฌํํด์ผ ํ๋ค.
ํน๋ณํ๊ฒ ์ปค์คํ ์ ์ผ ํ๋ ๋ถ๋ถ์ด ์๋ค๋ฉด, ์ผ๋จ ์ด๋ฐ์์ผ๋ก๋ง ๊ตฌํํ๋ฉด ๋๋ค.

struct promise {
coroutine get_return_object()
{
return coroutine{ coroutine::from_promise(*this) };
}
std::suspend_always initial_suspend() noexcept
{
return std::suspend_always{};
}
std::suspend_always final_suspend() noexcept
{
return std::suspend_always{};
}
std::suspend_never return_void() {
return std::suspend_never{};
}
void unhandled_exception() { std::puts("์์ธ ๋ฐ์"); }
};C++์ ์ฝ๋ฃจํด์ ํ๋์ ์ ํด์ง ํํ๊ฐ ์๋๊ฑด ์๋๊ณ , ์ด 3๊ฐ์ง์ ํํ๊ฐ ์๋ค๊ณ ํ ์ ์๋ค.
์ฌ์ค ์์์ ์ ์ํ ์ฝ๋ฃจํด ํ์
์ ์ฝ๋ฃจํด์ด๋ผ๊ณ ํ์ง๋ ์๊ณ , co_yield, co_await, co_return ์ค ํ๋ ์ด์์ ์ฌ์ฉํ ํจ์๋ฅผ ์ฝ๋ฃจํด์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
ํ๋์ฉ ๋ค๋ค๋ณด๊ฒ ๋ค.
co_yield ๊ตฌ๋ฌธ
co_yield ๊ตฌ๋ฌธ์ ์ฌ์ฉํด์ ์ ์ง์ ์ธ ์ํ ์ฒ๋ฆฌ๋ฅผ ์ํํ๋ ๋ฒ์ ๊ฐ๋ตํ ๋ค๋ค๋ณด๊ฒ ๋ค.
co_yield๋ ๋ค๋ฅธ ์ธ์ด์ ์ฝ๋ฃจํด ์ ํ์ค์ ๋์ผํ๊ฒ, ํจ์ ๋ด์์ ์ํ๋ฅผ ๋ง๋ค๊ณ ์์๋ก ๋ฆฌํด์ ํด์ฃผ๋ ๊ธฐ๋ฅ์ด๋ค.
๊ทธ๋์ ์ฝ๋ฃจํด์ ๋ค์ ํธ์ถํ๋ฉด ๊ทธ๋ ์์๋ก ๋ฆฌํดํ๋ ์ง์ ์ผ๋ก ๋์๊ฐ์ ๋ก์ง์ ๋ง์ ์ฒ๋ฆฌํ๋ค.
์ด๋ฅผ ์ด์ฉํ๋ฉด iterator ๋ฑ์ ๊ตฌํํ๊ธฐ ์ ์ ํ๋ค.
๋ด ๊ฒฝ์ฐ์๋ ๊ฐ๋จํ ์นด์ดํฐ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด๋ณด์๋ค.
// ์ฝ๋ฃจํด ๊ฐ์ฒด
template <class T>
struct coroutine: std::coroutine_handle<promise>{
struct promise {
coroutine get_return_object()
{
return coroutine(std::coroutine_handle<promise>::from_promise(*this));
}
std::suspend_always initial_suspend() noexcept
{
return {};
}
std::suspend_always final_suspend() noexcept
{
return {};
}
void return_void() {
}
void unhandled_exception() { std::puts("์์ธ ๋ฐ์"); }
T value;
std::suspend_always yield_value(T from) {
this->value = from; // caching the result in promise
return {};
}
};
using promise_type = struct promise;
std::coroutine_handle<promise> handle;
coroutine(std::coroutine_handle<promise> handle) {
this->handle = handle;
}
T operator()() {
handle(); // resume
auto result = handle.promise();
return result.value;
}
};
์ฝ๋ ํํ๊ฐ ์ข ๋ฌ๋ผ์ก๋ค.
ํ๋ก๋ฏธ์ค ํ์ ์๋ yield_value๋ผ๋ ํจ์์ ๋ฉค๋ฒ๋ณ์ T value;๊ฐ ์ถ๊ฐ๋์๋๋ฐ, ์ธ๋ถ์์ co_yield๋ฅผ ํธ์ถํ๋ฉด ๊ทธ ๊ฐ์ด yield_value๋ผ๋ ํจ์๋ก ๋์ด์ค๊ฒ ๋๋ค.
๊ทธ๋์ ๊ทธ๊ฑธ ์ ์ฅํด๋๊ณ , coroutine์์ ํํฐ๋ฅผ ํธ์ถํ๋ฉด ๊ทธ๊ฑธ ๋ค์ ๊บผ๋ด์ฃผ๋ ํํ๊ฐ ๋์๋ค.
์ด์ ๋ฐ์ค๋น๋ ๋์์ผ๋, ํจ์๋ง ์ ์ํ๋ฉด ๋๋ค.
coroutine<int> new_counter() {
int count = 0;
while (true) {
count++;
co_yield count; // ๋ฐํํ ํ, ๋ค์ ์คํ๋๋ฉด ๋ค์ ๋์์ด
}
}
๋ณ์๋ฅผ ํ๋ ๊น๊ณ ๋ฌดํ๋ฃจํ๋ฅผ ๋๋ฉด์ ๊ณ์ ๋ฐํํ๊ฒ ํ๋ค. ๊ฐ๋จํ๋ค.
๊ทธ๋ผ ์ด์ ์ฌ์ฉ์๋จ์์๋ ์ด๋ ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
๊ทธ๋ ๋ค.
co_return ๊ตฌ๋ฌธ
co_return์ ์ฝ๋ฃจํด์ ์ข
๋ฃ์ํค๋ ๋ช
๋ น์ด๋ค.
co_yield๊ฐ ์์๋ก ๋ฐํ๋ง ํด์ ๋ค์ ๋์์ฌ ์ ์์๋ค๋ฉด, co_return์ ์์ ์ข
๋ฃ๋ฅผ ์์ผ๋ฒ๋ฆฐ๋ค.
๋ง์ฝ ์ ์นด์ดํฐ ์ฝ๋์์ ์ซ์๊ฐ 3์ ๋๋ฌํ์๋ ์ข ๋ฃ๋ฅผ ์ํค๊ณ ์ถ๋ค๋ฉด, ๋ค์๊ณผ ๊ฐ์ด ํ ์ ์๋ค.
๊ทธ๋ผ ์ฝ๋ฃจํด์ด done ์ํ๊ฐ ๋๋๋ฐ, ์ด ์ํ์์ resume์ ์๋ํ๋ฉด ์์ธ๋ ์๋๊ณ ํ๋ก๊ทธ๋จ์ด ํฐ์ง๋ค.
์ดํด๋ ์๋์ง๋ง ๊ทธ๋ ๋ค.
๊ทธ๋์ ์ถ๊ฐ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ๊ณ

๋๋ฆฌ๋ฉด
์ด๋ ๊ฒ ๋์ํ ๊ฒ์ด๋ค.
co_await ๊ตฌ๋ฌธ
์ด๊ฑด ๋ค๋ฅธ ์ธ์ด์์ ์ฌ์ฉํ๋ async/await ์ ํ์ค์ ํก์ฌํ๋ค๊ณ ํ ์ ์๋ค.
์ฝ๋ฃจํด์ด ์ผ๋จ ์คํ๋๊ฒ ๋ ๋๋ค๊ฐ, co_await๋ฅผ ํธ์ถํ๋ฉด ํธ์ถ์๋ ํผํธ์ถ์(์ฝ๋ฃจํด)๊ฐ ๋๋๊ธฐ๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค.

๊ทธ๋ค์์๋ awaitableํ ํ์
์ ์ ์ํ๋ค.
์ฌ์ค ์์์ ์ด suspend_never์ suspend_always ๋ฑ๋ ์ด์ ๊ฐ์ ๊ตฌ์กฐ์ awaitable ๊ตฌํ์ผ ๋ฟ์ด๋ค.
await_ready๋ ํ์ฌ ์ฝ๋ฃจํด์ด ์์ ํ ์ข
๋ฃ๋ผ์ co_await๋ฅผ ๋ฐ์๋ค์ผ ์ ์๋์ง๋ฅผ ์ฒดํฌํ๋ ๋ฉ์๋๋ค.
๋๋ฌ์๋ true๋ฅผ ๋์ง๋ฉด ๋๋ค.
await_suspend๋ co_await๋ฅผ ์๋ฃํ ์ ์์๋(await_ready๊ฐ false์ผ๋), await_resume์ co_await๋ฅผ ์๋ฃํ ์ ์์ ๋(await_ready๊ฐ true์ผ๋) ํธ์ถ๋๋ค.
์ฌ๊ธฐ์๋ ๊ตณ์ด ์ฌ์ฉํ ์ผ์ด ์์ด์ ๋น์๋๋ค.
๊ทธ๋ค์์ ์ค๋ ๋ ์คํฐ์ ์ด๋ฐ์์ผ๋ก ๊ตฌ์ฑํ๊ณ

์ด๋ ๊ฒ ์ค๋ ๋๋ฅผ ์ด 2๊ฐ ๋์ ๋ค,
์ด 2๊ฐ์ ์ค๋ ๋๋ฅผ ์ฌ๋ฆฌ์ง๋ง, co_await์ผ๋ก ํธ๋ค๋ง์ ํด์ ์ฒซ๋ฒ์งธ ์ค๋ ๋๊ฐ ์ข
๋ฃ๋์ด await๋ ํ์ ๋๋ฒ์งธ ์ค๋ ๋๊ฐ ์คํ๋๋๋ก ํ๋ค.
๊ทธ๋ผ ์ด๋ ๊ฒ ๋์ํ ๊ฒ์ด๋ค.

์ฐธ์กฐ
https://en.cppreference.com/w/cpp/language/coroutines
https://kukuta.tistory.com/222
https://kukuta.tistory.com/224