cpp multithreading - pjy0121/Wiki GitHub Wiki
โ std::thread ์ฌ์ฉ โก std::jthread ์ฌ์ฉ โข std::async ์ฌ์ฉ
: ๊ธฐ๋ณธ thread ๊ฐ์ฒด. ๋ฐ๋์ detach๋ join์ ํธ์ถํด์ผ ํจ
- thread ๊ฐ์ฒด ์๋ฉธ ์ joinableํ ์ํ(detach ๋๋ joinํ์ง ์์ ์ํ)๋ผ๋ฉด std::terminate()๊ฐ ํธ์ถ๋์ด ํ๋ก๊ทธ๋จ์ด ๊ฐ์ ์ข ๋ฃ๋จ
๋ฉ์๋ | ์ญํ | ๋น๊ณ |
---|---|---|
join | ์์ฑ๋ thread๊ฐ ์ข ๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆผ | |
detach | thread๋ฅผ ๋ผ์ด๋ด์ด ๋ ๋ฆฝ์ ์ผ๋ก(๋ฐฑ๊ทธ๋ผ์ด๋) ์คํ | main thread๊ฐ ์ข ๋ฃ๋๋ฉด ํ๋ก๊ทธ๋จ์ด ์ข ๋ฃ๋๊ธฐ ๋๋ฌธ์ detach๋ thread๋ค๋ ํจ๊ป ์ข ๋ฃ๋๋ฏ๋ก ์ฃผ์ํด์ผ ํจ |
: ์ค๋จ ๊ฐ๋ฅํ๋ฉฐ joinํ ํ์๊ฐ ์๋ thread ๊ฐ์ฒด
std::thread๋ฅผ ์ธ ๋ ๋งค ๋ฒ join์ ํด์ผ ํ๋ฏ๋ก, thread ๊ฐ์ฒด๋ฅผ ๋ฉค๋ฒ๋ก ๊ฐ์ง๊ณ ์๋ class๋ฅผ ๋ง๋ค๊ณ ์๋ฉธ์์์ joinํ๋๋ก ํ๋ ๋ฐฉ์์ด ๋ง์ด ์ฐ์๋ ๊ฒ์ผ๋ก ๋ณด์
ex)
#include <iostream>
#include <thread>
class ThreadRAII {
public:
template<typename F, typename ... ARGS>
explicit ThreadRAII(F&& f, ARGS&&... args) : t(std::forward<F>(f), std::forward<ARGS>(args)...) {}
~ThreadRAII() {
if (t.joinable())
t.join();
}
std::thread& get() { return t; }
private:
std::thread t;
};
void func(int n) {
std::cout << "n : " << n << std::endl;
}
int main(void) {
ThreadRAII t(func, 1);
return 0;
}
ํ์ง๋ง C++20๋ถํฐ๋ ์๋ฉธ์์์ join์ ํธ์ถํด์ฃผ๋ std::jthread๋ฅผ ์ง์ํจ
ex)
int main(void) {
std::jthread t(func, 1);
return 0;
}
๋ํ jthread๋ Cooperatively Interruptible(ํ๋ ฅ์ ์ผ๋ก ์ค๋จ ๊ฐ๋ฅ)ํ๋ค๋ ํน์ฑ์ ๊ฐ์ง๊ธฐ ๋๋ฌธ์, ์คํํ ํจ์์ ์ธ์๋ก std::stop_token type์ ๋ฐ๋๋ก ํ๋ฉด ์ค๋จ ๊ฐ๋ฅํ thread๋ฅผ ๋ง๋ค ์ ์์. ๋ค๋ง ๋ค๋ฅธ thread์์ ์๋ฌด ๋๋ ์์ฒญํ๋ค๊ณ ์ค๋จ๋์ง๋ ์๊ณ , ์ค๋จ ์ง์ ์ ๋ฏธ๋ฆฌ ์ง์ ํด๋์ผ ํจ
ex)
[TODO] request_stop()๊ณผ stop_requested()๋ฅผ ์ฌ์ฉํ๋ ์์
: ๋น๋๊ธฐ thread ์์ฑ ํจ์
- caller๊ฐ callee์ ๊ฒฐ๊ณผ๊ฐ ๋์ฌ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋ ๋๊ธฐ ๋ฐฉ์์ ๋จ์ํ์ง๋ง callee์ ์์ ๊ณผ caller์ ๋จ์ ์์ ์ฌ์ด ์ฐ๊ด ๊ด๊ณ๊ฐ ์๋๋ผ๋ caller๊ฐ ๊ธฐ๋ค๋ ค์ผ ํ๋ฏ๋ก ๋นํจ์จ์ ์ผ ์ ์์ => ๋คํธ์ํฌ, ํ์ผ I/O, DB query, ์ค๋ ๊ฑธ๋ฆฌ๋ ์ฐ์ฐ, ์ฌ๋ฌ ๋ ๋ฆฝ์ ์์ ์ ๋์ ์ฒ๋ฆฌ ๋ฑ์์ ๋น๋๊ธฐ ๋ฐฉ์์ ์ฒ๋ฆฌ๊ฐ ๋ง์ด ์ฌ์ฉ๋จ
- ๋ด๋ถ์ ์ผ๋ก thread๋ฅผ ๋ง๋ค์ด ์ง์ ํ ํจ์๋ฅผ ์คํํ๊ณ future๋ฅผ ๋ฐํํจ
- ๊ธฐ๋ณธ์ ์ผ๋ก thread pool์ ์ฌ์ฉํ๋ฏ๋ก ํจ์จ์ ์
- launch option์ ํตํด thread์ ์คํ ์์ ์ ์ง์ ํ ์ ์์
launch option
- std::launch::async : ์๋ก์ด thread๋ฅผ ์์ฑํ์ฌ ํจ์๋ฅผ ์ฆ์ ์คํ
- std::launch::deferred : ํจ์๋ฅผ ์ฆ์ ์คํํ์ง ์๊ณ , get()์ด๋ wait()์ด ํธ์ถ๋ ๋(๊ฒฐ๊ณผ๊ฐ ํ์ํ ์๊ฐ)๊น์ง ์ง์ฐ์ํด
- std::launch::async | std::launch::deferred : ์คํ ํ๊ฒฝ์ ๋ฐ๋ผ ๋ ์ค ํ๋๋ฅผ ์ ํํ์ฌ ์คํ (๊ธฐ๋ณธ๊ฐ)
[TODO] launch option์ ์ฌ์ฉํ async ์์
async ํจ์์์ return๋๋ future์ ์๋ฉธ์์์๋ get ํจ์๊ฐ ํธ์ถ๋๋ฏ๋ก ๋ค์์ ์ฃผ์ํด์ผ ํจ
- return๊ฐ์ ๋ฐ์์ง๋ง get()์ ํธ์ถํ์ง ์์ ๊ฒฝ์ฐ ํจ์์์ return๋ future ๊ฐ์ฒด๊ฐ ๋ณต์ฌ๋์ด ๋ณ์์ ์ ์ฅ๋ ํ caller ํจ์๊ฐ ๋๋ ๋ ์๋ฉธ๋๋ฏ๋ก caller ํจ์๊ฐ ์ข ๋ฃ๋์ง ์๊ณ thread์ ์ข ๋ฃ๋ฅผ ๊ธฐ๋ค๋ฆผ
int add(int a, int b) {
cout << "start add " << endl;
this_thread::sleep_for(chrono::seconds(3));
cout << "end add" << endl;
return a + b;
}
int main() {
cout << "start main" << endl;
future<int> ft = async(add, 10, 20);
cout << "end main" << endl;
return 0;
}
[์ถ๋ ฅ]
start main end main start add end add
- return๊ฐ์ ๋ฐ์ง ์๊ณ ํธ์ถํ ๊ฒฝ์ฐ future๊ฐ ์์ ๊ฐ์ฒด๋ก ์์ฑ๋์ด, ํจ์๋ฅผ ํธ์ถํ ์ง์ ์์ ๋ค์ ์ฝ๋๋ก ๋์ด๊ฐ์ง ์๊ณ thread์ ์ข ๋ฃ๋ฅผ ๊ธฐ๋ค๋ฆผ. ์ด๋ฐ ๋ถ๋ถ์ด ์์ ๊ฒฝ์ฐ ๋ณดํต ์ปดํ์ผ๋ฌ๊ฐ warning์ ๋ด์ค
int main() {
cout << "start main" << endl;
future<int> ft = async(add, 10, 20);
cout << "end main" << endl;
return 0;
}
[์ถ๋ ฅ]
start main start add end add end main