ใ์ถ์ฒ. ์์ํ์! C++17 ํ๋ก๊ทธ๋๋ฐ (๋ฐํ์ฌ ์ง์)ใ
๋ ๋ฆฝ์ ์ผ๋ก ์คํ๋๋ ์ค๋ ๋๋ผ ํ๋๋ผ๋ ๊ฒฝ์ฐ์ ๋ฐ๋ผ ๋ค๋ฅธ ์ค๋ ๋์ ์ ๋ฌํ ์ ๋ณด๊ฐ ์๊ธฐ ๋ง๋ จ์ด๋ค. ์ ๋ฌํ๋ ๋ฐฉ๋ฒ ์ค ์ฐ๋ฆฌ๊ฐ ๊ณต๋ถํ ๋ฐฉ๋ฒ์ '์กฐ๊ฑด๋ณ์(Conditional Variable)' ๋ผ๊ณ ๋ถ๋ฅด๋ ๊ธฐ๋ฅ์ด๋ค.
์กฐ๊ฑด๋ณ์๋ ์ฃผ๋ก ๊ฒ์์์ ๋ง์ด ์ฌ์ฉํ๋ ๋ฐ ๋ฌ๋ฆฌ๊ธฐ ์ํฉ์ฒ๋ผ ๋ชจ๋ ์ ์๊ฐ ์ถ๋ฐ์ ์์ ๋๊ธฐํ ์ํ์์ ์ด์๋ฆฌ์ ํจ๊ป ์ถ๋ฐํ๋๋ก ์ค๋ ๋ ๋ชจ๋ ๋๊ธฐ ์ํ๋ก ๋ง๋ค๊ณ ๋์์ ๊ณต๋ ๊ฒฝ์์ ์ํํ๋ค.
์กฐ๊ฑด๋ณ์๋ ๋จ์ง ๋ณ์๋ฅผ ํตํด ์ ํธ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ๊ธฐ๋ฅ๋ง์ ์ ๊ณตํ ๋ฟ ์์ฒด ์ ๊ธ ๊ธฐ๋ฅ์ด ์๋ค. ๋ฐ๋ผ์ ๋ค์์ ์ค๋ ๋์ ์ํด ์คํ๋๋ ์์ ์ด ์์ ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ๋ณ๋ ๋ฎคํ ์ค๋ฅผ ์ฌ์ฉํ๋ค.
๊ฐ์ฅ ์ค์ํ ํจ์๋ wait(), notify_all() ํจ์์ด๋ค.
์กฐ๊ฑด๋ณ์๊ฐ ์ ํธ๋ฅผ ๋ฐ์ผ๋ฉด, ์์ ์ ์ํํ๊ธฐ ์ ์ ๊ฐ์ฅ ๋จผ์ wait()ํจ์ ๋ด๋ถ์์ ๋ฎคํ ์ค์ ๋ํ ์ ๊ธ์ ๋ค์ ์ค์ ํ๊ณ ์๊ณ ๊ตฌ์ญ์ผ๋ก ์ง์ ํ์ฌ ์์ ์ ์ํํ๋ค.
โป์๊ณ๊ตฌ์ญ
1. void wait(std::unique_lock<std::mutex>& lock)
๋ค๋ฅธ ์ค๋ ๋๋ก๋ถํฐ ์ ํธ๋ฅผ ๋ฐ์ ๋๊น์ง ๋๊ธฐํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. ์ด๋ ์๊ณ ๊ตฌ์ญ ๋ด ์กด์ฌํ๋ ์์ ์ ์ํํ๊ธฐ ์ํด ๋ฎคํ ์ค๋ฅผ ์ฌ์ฉํ๋ค. ์ฃผ์์ ์ wait()ํจ์๋ฅผ ํธ์ถํ๊ธฐ ์ ์ ๋จผ์ ๋ฎคํ ์ค์ ์ ๊ธ์ ์ค์ ํด์ผ ํ๋ค.
์กฐ๊ฑด ๋ณ์์ ์ ํธ๋ฅผ ๋ฐ์๋ค ํ๋๋ผ๋ ๋ฎคํ ์ค์ ์ ๊ธ์ด ์ค์ ๋์ด ์์ผ๋ฉด ํด์ ๋ ๋๊น์ง ๋๊ธฐํ๊ฒ ๋๋ค.
2. void notify_all()
์กฐ๊ฑด ๋ณ์์ ์ ํธ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ wait()ํจ์์ ์ ํธ๋ฅผ ์ ์กํ๋ค.
์ ํธ๋ฅผ ๋ฐ์ ์ค๋ ๋๋ ์ฆ์ ๊นจ์ด๋์ ์คํ๋๋ ๊ฒ์ด ์๋๋ผ ์ ํธ๋ฅผ ๋ฐ์ํ ์ค๋ ๋๊ฐ ๋ฎคํ ์ค์ ์ ๊ธ์ ํด์ฌ์ํฌ ๋ ๋น๋ก์ ์ ํธ๋ฅผ ์ ๋ฌ๋ฐ์ ์ค๋ ๋๋ ์๋ํ๊ฒ ๋๋ค.
์์ ์ด ์๋ฃ๋์ด ํ๋ก๊ทธ๋จ ์ ์ด๊ฐ ์ง์ญ ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ค๋ฉด std::unique_lock ํด๋์ค์ ํน์ฑ์ ๋ฐ๋ผ ๋ฎคํ ์ค์ ์ ๊ธ์ด ์๋์ผ๋ก ํด์ ๋๋ ๋์์ ๊ฐ์ฒด๊ฐ ์๋ฉธ๋๋ค.
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
static int ranking = 1;
void print(int id)
{
// ๋ฎคํ
์ค์ ํจ๊ป unique_lock ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์ ๊ธ์ ์ค์
std::unique_lock<std::mutex> umtx(mtx);
// ์กฐ๊ฑด๋ณ์ ํด๋์ค๊ฐ ์ ๊ณตํ๋ wait()ํจ์๋ฅผ ํธ์ถํ๊ณ ์กฐ๊ฑด ๋ณ์์ ์ ํธ๋ฅผ ๊ธฐ๋ค๋ฆผ.
// wait()ํจ์๋ ๋ด๋ถ์์ ์์์ ์ค์ ํ ๋ฎคํ
์ค์ ์ ๊ธ์ ํด์ ์ํค๊ณ ์กฐ๊ฑด ๋ณ์
// ํตํด ์ ํธ๊ฐ ๋ค์ด์ค๊ธฐ๊น์ง ๋๊ธฐํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
cv.wait(umtx);
std::cout << ranking++ << ". thread" << id << "\n";
}
int main()
{
std::thread threads[10];
for (int i = 0; i < 10; ++i)
{
//์์
์ ์ํํ ์ค๋ ๋๋ฅผ ์์ฑํ๊ณ ์ค๋ ๋๋ฅผ ์คํ์ํจ๋ค.
threads[i] = std::thread(print, i);
}
std::cout << "10๊ฐ์ ์ค๋ ๋๊ฐ ๋ ์ด์ค ๊ฒฝ์๋ฅผ ํผ์น๋ค.\n";
//๋ชจ๋ ์ค๋ ๋๊ฐ wait()ํจ์๋ฅผ ํธ์ถํ ๋๊น์ง ์ ์ ๋๊ธฐํ๋ค.
std::this_thread::sleep_for(std::chrono::milliseconds(10));
{
std::unique_lock<std::mutex> umtx(mtx);
cv.notify_all();//๋ชจ๋ ์ค๋ ๋์ ์ ํธ๋ฅผ ๋ณด๋ธ๋ค.
/*๋ฎคํ
์ค ์ ๊ธ์ ์ค์ ๋์๋ค๋ ์๋ฏธ๋ ๋ชจ๋ ์ผ๋ฐ ์ค๋ ๋์์ wait()ํจ์๋ฅผ
ํธ์ถํ๊ณ ๋ฎคํ
์ค์ ์ ๊ธ์ ํด์ ์์ผฐ๋ค๋ ์๋ฏธ๊ฐ ๋๋ค. ๋ฐ๋ผ์ ๋ฎคํ
์ค ์ ๊ธ์ ์ค์
ํ๊ณ ์๊ณ๊ตฌ์ญ์ผ๋ก ์ง์
ํ์ฌ ๋ชจ๋ ์กฐ๊ฑด ๋ณ์์ ์ ํธ๋ฅผ ๋ณด๋ด ์์
๊ฐ์๋ฅผ ์๋ฆฐ๋ค.*/
}
for (auto& th : threads) th.join();
return 0;
}
๋ฉ์ธ์ค๋ ๋๊ฐ ๋ณด๋ธ ์ ํธ๋ ๋ชจ๋ ์ผ๋ฐ ์ค๋ ๋์ ๊ฑฐ์ ๋์์ ์ ํธ๋ฅผ ๋ณด๋์ง๋ง, ๊ทธ ๊ฐ์ด๋ฐ ๊ฐ์ฅ ๋จผ์ ์ ํธ๋ฅผ ๋ฐ์ ์ค๋ ๋๊ฐ ๊ฐ์ฅ ๋จผ์ ํด์ ๋ ๋ฎคํ ์ค์ ๋ํด ์ ๊ธ์ ์ค์ ํ๋ค.
์ ํธ๋ฅผ ๋ฐ์ ๋ค๋ฅธ ์ค๋ ๋๋ ์ด๋ ํ๋์ ์ค๋ ๋์ ์ํด ๋ฎคํ ์ค ์ ๊ธ์ด ์ค์ ๋์ด์๊ธฐ ๋๋ฌธ์ ๋ค์ ๋๊ธฐ ์ํ์ ๋ค์ด๊ฐ๊ฒ ๋๋ค. ๋ฎคํ ์ค ์ ๊ธ์ ์ค์ ํ ์ค๋ ๋๊ฐ ์์ ์ ๋ง๋ฌด๋ฆฌํ๊ณ ๋ฎคํ ์ค์ ์ ๊ธ์ ํผ๋ค๋ฉด ๊ทธ ๋ ๋๋จธ์ง ์ค๋ ๋๋ค์ด ์์ฐจ์ ์ผ๋ก ๋ฎคํ ์ค์ ์ ๊ธ์ ์ค์ ํ๊ณ ์์ ์ ๋ง๋ฌด๋ฆฌํ๊ฒ ๋๋ค.
์กฐ๊ฑด๋ณ์ ํด๋์ค๊ฐ ์ ๊ณตํ๋ ํจ์๋?
โ void wait(std:: unique_lock<std::mutex>& lock) : <mutex>
wait()ํจ์๋ ๋ค๋ฅธ ์ค๋ ๋๋ก๋ถํฐ ์ ํธ๋ฅผ ๋ฐ์ ๋๊น์ง ๋๊ธฐํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
โ template<class Predicate>
void wait(std::unique_lock<std::mutex>& lock, Predicate pred) : <mutex>
์์ ๋ ๋ฒ์งธ ์ธ์๋ก ์ ๊ณต๋ pred๋ bool ํ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ ํจ์๋ก ๋ค์๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ์ํํ๋ค.
while(!pred()) {
cv.wait(umtx);
}
ํจ์๊ฐ ๊ฑฐ์ง์ด๋ฉด ๋ฐ๋ณต ์์ ์ ์ํํ๋ค.
โ template <class Rep, class Period>
cv_state wait_for(unique_lock<mutex>&lck, const chrono::duration<Rep, Period>& rel_time) : <mutex>
โ template <class Rep, class Period, class Predicate>
bool wait_for (unique_lock<mutex>& lck, const chrono::duration<Repm Period>& rel_time, Predicate pred) : <mutex>
๊ฐ์ ๊ธฐ๋ฅ์ด์ง๋ง ๋๊ธฐํ๋ ์๊ฐ ๊ฐ๊ฒฉ์ด ์ค์ ๋์ด ์์ด ์๊ฐ ๊ฐ๊ฒฉ์ ๋๋๋ค๋ฉด ๊ทธ์ ๋ฐ๋ผ ๊ฐ๊ฐ ๋ค๋ฅธ ๋ฐํ๊ฐ์ ๋ฐํํ๋ค.
โ template<class Clock, class Duration>
std::cv_status wait_until(std::unique_lock<std::mutex>& lock, const std::chrono::time_point<Clockm Duration>&
timeout_time) : <mutex>
โ template <class Clock, class Duration, class Predicate>
bool wait_until (std::unique_lock<std::mutex>& lock, const std::chrono::time_point<Clock, Duration>& timeout_time, Predicate pred) : <mutex>
์ฃผ์ด์ง ์๊ฐ ๊ฐ๊ฒฉ์ด ์๋ ๋ฏธ๋์ ์๊ฐ์ ๊ธฐ์ค์ผ๋ก ํ๋ค.
โ void notify_all() noexcept
โ void notify_one() noexcept
notify_allํจ์๋ ์กฐ๊ฑด ๋ณ์์ ์ ํธ๋ฅผ ๋๊ธฐํ๋ ๋ชจ๋ ์ค๋ ๋์ ๊ฑฐ์ ๋์์ ์ ํธ๋ฅผ ์ ์กํ๋ค.
๋ฐ๋ฉด์ notify_one()ํจ์๋ ์กฐ๊ฑด ๋ณ์์ ์ ํธ๋ฅผ ๋๊ธฐํ๋ ์ค๋ ๋ ๊ฐ์ด๋ฐ ํ๋์ ์ค๋ ๋๋ฅผ ์ ํํ์ฌ ์ ํธ๋ฅผ ์ ๋ฌํ๋ค.
โป noexcept ? c++ํจ์์ ํค์๋๋ก 'noexcept ํค์๋๋ฅผ ๋ถ์ด๋ฉด ํด๋น ํจ์๊ฐ ์์ธ๋ฅผ throw ํ์ง ์๋๋ค' ์ด๊ฒ ๋ฌด์จ ๋ง์ธ์ง ์ค๋ช ํ๋ฉด C++์์๋ ํจ์๊ฐ ์์ธ ์ฒ๋ฆฌ๋ฅผ ํ๋ ๋ฐฉ๋ฒ์ 2๊ฐ์ง๊ฐ ์๋๋ฐ ํจ์๊ฐ ์์ธ๋ฅผ ๋์ง ๊ฐ๋ฅ์ฑ์ด ์๋์ง ์๋๋ฉด ์ ๋ ์์ธ๋ฅผ ๋์ง์ง ์๋์ง ์ด๋ ๊ฒ ๋๊ฐ์ง ๋ฐฉ๋ฒ์ด ์๋๋ฐ ํ์ ๋ฐฉ๋ฒ์ด noexcept ํค์๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
๋ง์ฝ noexcept๋ก ๋ช ์๋ ํจ์๊ฐ ์์ธ๋ฅผ ๋ฐ์์ํจ๋ค ํด๋ ์์ธ๊ฐ ์ ๋๋ก ์ฒ๋ฆฌ๋์ง ์๊ณ ํ๋ก๊ทธ๋จ์ ์ข ๋ฃ ๋ฉ๋๋ค.
'๐จ๐ปโ๐ป programming > โฝ c, c++' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[C++] ์ ๋ค๋ฆญ ์๊ณ ๋ฆฌ์ฆ ๋ชจ์ (0) | 2022.05.16 |
---|---|
[C++] std::string_view ํด๋์ค (0) | 2022.02.09 |
[C++] ์ฐ์ฐ์ ์ค๋ฒ๋ก๋ฉ ํ๋กํ ํ์ & ํ๊ณ (0) | 2022.02.08 |
(์ ๋ฌธ๊ฐ๋ฅผ ์ํ C++/ ๊ฐ์ 4ํ) - I/O ์ ์ถ๋ ฅ ์์ ๋ถ์ (0) | 2022.01.31 |
[C++] ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ (0) | 2021.03.14 |
์ ํ๋ ๊ฒ ๋ณด๋ค ๋ซ๊ฒ ์ง
ํฌ์คํ ์ด ์ข์๋ค๋ฉด "์ข์์โค๏ธ" ๋๋ "๊ตฌ๋ ๐๐ป" ํด์ฃผ์ธ์!