์ง๋ ํฌ์คํ ์์๋ ๋ฉํฐ์ค๋ ๋์ ๋ฉํฐ ํ๋ก์ธ์ค, std::thread์ ๋ํด ์ดํด๋ดค์ต๋๋ค. [C++] 20. ๋ฉํฐ ์ค๋ ๋ ํ๋ก๊ทธ๋๋ฐ(Multi-Threads)
์ค๋์ ์ด์ด์ ์ค๋ ๋๋ผ๋ฆฌ์ ์ถฉ๋ ๋ฌธ์ ์ lock ๋ฌธ์ ๋ฅผ ์ดํด๋ณด๊ณ , ์ค๋ ๋๋ค(workers)์ด wait์ํ์์ ๋๊ธฐํ๋ค๊ฐ ์์ ์ด ์์ ๋ ์์์ ์ฒ๋ฆฌํ๋ ์ค๋งํธํ ์ด์๋ฐฉ์์ ๋ํด ์์๋ณด๊ณ ์ ํฉ๋๋ค.
๊ณต์ ์์(Shared Resources)๊ณผ ์๊ณ์์ญ(Critical Section)
์ค๋ ๋(Thread)๋ ํ๋ก์ธ์ค ๋ด์์ ์คํ๋๋ ์์ ์คํ ๋จ์๋ก, ํ๋์ ํ๋ก์ธ์ค ์์ ์ฌ๋ฌ ๊ฐ์ ์ค๋ ๋๊ฐ ์กด์ฌํ ์ ์์ต๋๋ค. ์ด๋ ์ค๋ ๋ ๊ฐ์๋ ๊ณต์ ์์(Shared Resource)๊ณผ ๊ด๋ จ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๊ณต์ ์์์ ์์ ํ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํด ์๊ณ์์ญ(Critical Section)์ด๋ผ๋ ๊ฐ๋
์ด ๋ฑ์ฅํฉ๋๋ค.
๊ณต์ ์์์ ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ์ ๊ทผํ๊ฑฐ๋ ์์ ํ ์ ์๋ ๋ฐ์ดํฐ๋ ์์์ ๋งํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ, ํ์ผ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฑ์ด ๊ณต์ ์์์ ํด๋นํ ์ ์์ต๋๋ค. ์ค๋ ๋๋ค์ ์ด๋ฌํ ๊ณต์ ์์์ ์ ๊ทผํ๊ฑฐ๋ ์์ ํ๋ ์์
์ ์ํํ ์ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ๊ณต์ ์์์ ์ ๊ทผํ๊ฑฐ๋ ์์ ํ๋ ค๊ณ ํ ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. ์ด๋ ์๊ณ์์ญ์ด๋, ๊ณต์ ์์์ ๋ํ ์ ๊ทผ์ ๋๊ธฐํํ์ฌ ํ ๋ฒ์ ํ๋์ ์ค๋ ๋๋ง์ด ์๊ณ์์ญ์ ์ง์
ํ์ฌ ์์
์ ์ํํ๋๋ก ํ๋ ๋ถ๋ถ์ ๋งํฉ๋๋ค. ์ด๋ ๋ค์์ ์ค๋ ๋๊ฐ ๊ณต์ ์์์ ์์ ํ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํด ํ์ํ ๋ฉ์ปค๋์ฆ์
๋๋ค.
์๊ณ์์ญ์ ๊ด๋ฆฌํ๊ธฐ ์ํ ๊ธฐ๋ฒ์๋ ๋ฎคํ
์ค(Mutex), ์ธ๋งํฌ์ด(Semaphore), ์ค๋ ๋-๋ก์ปฌ ์ ์ฅ์(Thread-Local Storage) ๋ฑ์ด ์์ต๋๋ค. ์ด๋ฌํ ๋๊ธฐํ ๊ธฐ๋ฒ์ ์ฌ์ฉํ์ฌ ์ค๋ ๋๋ค์ด ์๊ณ์์ญ์ ์ ๊ทผํ ๋ ์๋ก์ ์์
์ด ๊ฒน์น์ง ์๋๋ก ๋ณด์ฅํ ์ ์์ต๋๋ค. ์ด๋ก์จ ๋ฐ์ดํฐ ์ผ๊ด์ฑ๊ณผ ์์ ์ฑ์ ์ ์งํ๋ฉด์ ๊ณต์ ์์์ ์ฌ์ฉํ ์ ์๊ฒ ๋ฉ๋๋ค.
์์ฝํ์๋ฉด, ์ค๋ ๋ ๊ฐ์ ๊ณต์ ํ๋ ์์์ ์ ๊ทผํ ๋ ๋ฐ์ํ ์ ์๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์๊ณ์์ญ์ด๋ผ๋ ๊ฐ๋
์ด ๋ฑ์ฅํฉ๋๋ค. ์๊ณ์์ญ์ ๋๊ธฐํ ๊ธฐ๋ฒ์ ํตํด ์ฌ๋ฌ ์ค๋ ๋๊ฐ ์์ ํ๊ฒ ๊ณต์ ์์์ ์ฌ์ฉํ ์ ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
๊ฒฝ์์ํ(Race Condition)
์ค๋ ๋์ ๊ฒฝ์์ํ(Race Condition)๋ ์ฌ๋ฌ ๊ฐ์ ์ค๋ ๋๊ฐ ๊ณต์ ์์์ ์ ๊ทผํ๊ฑฐ๋ ์์ ํ๋ ค๊ณ ํ ๋, ์ค๋ ๋๋ค์ ์คํ ์์์ ์์กดํ์ฌ ์์์น ๋ชปํ ๊ฒฐ๊ณผ๊ฐ ๋ฐ์ํ๋ ์ํฉ์ ๋งํฉ๋๋ค. ์ด๋ฌํ ์ํฉ์ ์ค๋ ๋ ๊ฐ์ ๊ฒฝ์์ผ๋ก ์ธํด ๋ฐ์ํ๋ฉฐ, ํ๋ก๊ทธ๋จ์ ์คํ ๊ฒฐ๊ณผ๊ฐ ์ผ๊ด๋์ง ์๊ฑฐ๋ ์๋ชป๋ ๊ฒฐ๊ณผ๊ฐ ๋์ฌ ์ ์์ต๋๋ค.
๊ฒฝ์์ํ๋ ์ฃผ๋ก ๊ณต์ ์์์ ๋ํ ์ ๊ทผ์ด๋ ์์ ์ด ๋๊ธฐํ ์์ด ์ด๋ฃจ์ด์ง๋ ๊ฒฝ์ฐ์ ๋ฐ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ๊ฐ์ ๋ณ์๋ฅผ ์ฝ๊ฑฐ๋ ์์ ํ๋ ค๊ณ ํ ๋ ๋ฐ์ํ ์ ์์ต๋๋ค. ๋ง์ฝ ์ด๋ฌํ ์์
์ด ์๋ชป๋ ์์๋ก ์ด๋ฃจ์ด์ง๋ฉด, ์์์น ๋ชปํ ๊ฐ์ด๋ ์ค์๋์ด ๋ฐ์ํ ์ ์์ต๋๋ค.
๊ฒฝ์์ํ๋ ๋ค์ํ ๋ฌธ์ ๋ฅผ ์ผ๊ธฐํ ์ ์๋๋ฐ, ๊ทธ ์ค ์ผ๋ฐ์ ์ธ ๋ฌธ์ ๋ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. ๋ฐ์ดํฐ ์ผ๊ด์ฑ ๋ฌธ์ : ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๋์์ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ ๊ฒฝ์ฐ, ์ค๋ ๋ ๊ฐ์ ๋ฐ์ดํฐ๊ฐ ์ผ๊ด์ฑ ์์ด ๋ณ๊ฒฝ๋์ด ์์์น ๋ชปํ ๊ฒฐ๊ณผ๋ฅผ ์ด๋ํ ์ ์์ต๋๋ค.
2. ๊ต์ฐฉ์ํ(Deadlock): ๋ ๊ฐ ์ด์์ ์ค๋ ๋๊ฐ ์๋ก ์๋๋ฐฉ์ด ์ ๊ทผํ๊ณ ์๋ ์์์ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ๋ฌดํํ ๋๊ธฐํ๋ ์ํ๋ก, ํ๋ก๊ทธ๋จ์ด ๋ฉ์ถ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
3. ์ฐ๊ธฐ ํ ์ฝ๊ธฐ ๋ฌธ์ : ํ ์ค๋ ๋๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ ๋์ค์ ๋ค๋ฅธ ์ค๋ ๋๊ฐ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ผ๋ฉด, ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ์ด ๊นจ์ง ์ ์์ต๋๋ค.
4. ์ธํฐ๋ฝํธ ๋ฌธ์ : ์ธํฐ๋ฝํธ๋ ํ์ด๋จธ ๋ฑ์ ์ธ๋ถ ์์ธ์ผ๋ก ์ธํด ์ค๋ ๋์ ์คํ์ด ์ค๋จ๋ ๋, ๊ณต์ ์์์ ์ํ๊ฐ ์ผ๊ด๋์ง ์์ ์ ์์ต๋๋ค.
์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์๋ ์ค๋ ๋ ๊ฐ์ ๋๊ธฐํ ๋ฉ์ปค๋์ฆ์ ์ฌ์ฉํ์ฌ ๊ฒฝ์์ํ๋ฅผ ๋ฐฉ์งํ๊ฑฐ๋ ์ ์ดํด์ผ ํฉ๋๋ค. ๋ฎคํ
์ค(Mutex), ์ธ๋งํฌ์ด(Semaphore), ์๊ณ์์ญ(Critical Section) ๋ฑ์ ๊ธฐ๋ฒ์ ํ์ฉํ์ฌ ๊ณต์ ์์์ ์ ๊ทผ์ ์กฐ์ ํจ์ผ๋ก์จ ๊ฒฝ์์ํ๋ฅผ ํผํ๊ณ ํ๋ก๊ทธ๋จ์ ์์ ์ฑ์ ํ๋ณดํ ์ ์์ต๋๋ค.
๋ฐ๋๋ฝ(Dead Lock)
๋ฐ๋๋ฝ(Deadlock)์ ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ๋ฐ์ํ๋ ๋๊ธฐํ ๋ฌธ์ ์ค ํ๋๋ก, ๋ ๊ฐ ์ด์์ ์ค๋ ๋๋ ํ๋ก์ธ์ค๊ฐ ์๋ก๊ฐ ๊ฐ์ง ์์์ ์ ์ ํ๊ณ ์์ด์ ๊ณ์ํด์ ์๋๋ฐฉ์ด ์ ์ ํ๊ณ ์๋ ์์์ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ์๋ฌด ๋์๋ ์ํํ์ง ๋ชปํ๋ ์ํ๋ฅผ ๋งํฉ๋๋ค. ์ด๋ฌํ ์ํฉ์์๋ ๊ฐ ์ค๋ ๋๋ ํ๋ก์ธ์ค๊ฐ ๋ค์ ๋จ๊ณ๋ก ์งํํ์ง ๋ชปํ๋ฏ๋ก, ํ๋ก๊ทธ๋จ์ด ๋ฌดํํ ๋ฉ์ถ ๊ฒ์ฒ๋ผ ๋ณด์ผ ์ ์์ต๋๋ค.
๋ฐ๋๋ฝ์ด ๋ฐ์ํ๋ ค๋ฉด ์๋์ ๋ค ๊ฐ์ง ์กฐ๊ฑด์ด ๋ชจ๋ ์ถฉ์กฑ๋์ด์ผ ํฉ๋๋ค.
1. ์ํธ ๋ฐฐ์ (Mutual Exclusion): ์์์ ํ ๋ฒ์ ํ๋์ ์ค๋ ๋๋ ํ๋ก์ธ์ค๋ง์ด ์ฌ์ฉํ ์ ์์ด์ผ ํฉ๋๋ค. ์ฆ, ํ ์์์ ๋์์ ์ฌ๋ฌ ์ค๋ ๋๋ ํ๋ก์ธ์ค์ ์ํด ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
2. ์ ์ ์ ๋๊ธฐ(Hold and Wait): ์ต์ํ ํ๋์ ์์์ ์ ์ ํ ์ํ์์ ๋ค๋ฅธ ์์์ ๊ธฐ๋ค๋ฆฌ๋ ์ค๋ ๋๋ ํ๋ก์ธ์ค๊ฐ ์์ด์ผ ํฉ๋๋ค.
3. ๋น์ ์ (No Preemption): ๋ค๋ฅธ ์ค๋ ๋๋ ํ๋ก์ธ์ค์ ์ํด ์ ์ ๋ ์์์ ๊ฐ์ ๋ก ๋นผ์์ ์ ์์ด์ผ ํฉ๋๋ค. ์์์ ํด๋น ์ค๋ ๋๋ ํ๋ก์ธ์ค๊ฐ ๋ฐ๋ฉํ๊ธฐ ์ ๊น์ง ์ ์ ๋์ด์ผ ํฉ๋๋ค.
4. ์ํ ๋๊ธฐ(Circular Wait): ๊ฐ ์ค๋ ๋๋ ํ๋ก์ธ์ค๋ ๋ค์ ์ค๋ ๋๋ ํ๋ก์ธ์ค๊ฐ ์ ์ ํ ์์์ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ์ํ์ผ๋ก ๋๊ธฐํ๋ ์ํฉ์ด์ด์ผ ํฉ๋๋ค.
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx1;
std::mutex mtx2;
void threadFunction1() {
std::lock_guard<std::mutex> lock1(mtx1);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // ์ ์ ๋๊ธฐ
std::cout << "Thread 1 locked mtx1" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // ์ ์ ๋๊ธฐ
std::lock_guard<std::mutex> lock2(mtx2);
std::cout << "Thread 1 locked mtx2" << std::endl;
}
void threadFunction2() {
std::lock_guard<std::mutex> lock2(mtx2);
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // ์ ์ ๋๊ธฐ
std::cout << "Thread 2 locked mtx2" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // ์ ์ ๋๊ธฐ
std::lock_guard<std::mutex> lock1(mtx1);
std::cout << "Thread 2 locked mtx1" << std::endl;
}
int main() {
std::thread t1(threadFunction1);
std::thread t2(threadFunction2);
t1.join();
t2.join();
return 0;
}
์ ์์ ์์๋ ๋ ๊ฐ์ ์ค๋ ๋๊ฐ ๊ฐ์ ํจ์๋ฅผ ์คํํ๋ฉด์ ๋ ๊ฐ์ ๋ฎคํ ์ค(mtx1, mtx2)๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. Function1์์๋ mtx1์ ์ ์ ํ ์ฑ๋ก mtx2๋ฅผ ์ ์ ํ๋ ค๊ณ ํ๊ณ , Function2์์๋ mtx2๋ฅผ ์ ์ ํ ์ฑ๋ก mtx1์ ์ ์ ํ๋ ค๊ณ ํฉ๋๋ค. ๋ฐ๋๋ฝ์ด ๊ฑธ๋ฆฐ ์ํฉ์ ๋๋ค.
์ค์ ํ๋ก๊ทธ๋๋ฐ์์๋ ์ด๋ฌํ ๋ฐ๋๋ฝ ์ํฉ์ ํผํ๊ณ ์ ๋ฎคํ ์ค๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๊ณ , ์์๋๋ก ์ ์ ํ๊ฑฐ๋ ํ๋ํ๋ ๋ฑ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ๋ฐ๋๋ฝ์ ์๋ฐฉํด์ผ ํฉ๋๋ค.
๋ฎคํ ์ค(Mutex)
๋ฎคํ
์ค(Mutex)๋ ์ํธ ๋ฐฐ์ (Mutual Exclusion)๋ฅผ ๊ตฌํํ๊ธฐ ์ํ ๋๊ธฐํ ๊ธฐ๋ฒ ์ค ํ๋๋ก, ์ฌ๋ฌ ๊ฐ์ ์ค๋ ๋๋ ํ๋ก์ธ์ค๊ฐ ๊ณต์ ์์์ ๋์์ ์ ๊ทผํ๋ ๊ฒ์ ๋ง๋ ์ญํ ์ ํฉ๋๋ค. ๋ฎคํ
์ค๋ ํ ๋ฒ์ ํ๋์ ์ค๋ ๋๋ง์ด ํน์ ์์์ ์ฌ์ฉํ ์ ์๋๋ก ์ ์ดํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
๋ฎคํ
์ค๋ ํฌ๊ฒ ๋ ๊ฐ์ง ์ํ๋ฅผ ๊ฐ์ง๋๋ค.
1. ์ ๊ธ(Locked) ์ํ: ๋ฎคํ
์ค๊ฐ ๋ค๋ฅธ ์ค๋ ๋์ ์ํด ์ ๊ฒจ์ ธ ์๋ ์ํ๋ก, ํด๋น ์์์ ์ ๊ทผํ ์ ์์ต๋๋ค.
2. ์ ๊ธ ํด์ (Unlocked) ์ํ: ๋ฎคํ
์ค๊ฐ ๋ค๋ฅธ ์ค๋ ๋์ ์ํด ์ ๊ธ ํด์ ๋์ด ํด๋น ์์์ ์ ๊ทผํ ์ ์๋ ์ํ์
๋๋ค.
๋ฎคํ
์ค๋ฅผ ์ฌ์ฉํ๋ ์ผ๋ฐ์ ์ธ ํจํด์ ์ค๋ ๋๊ฐ ์์์ ์ ๊ทผํ๊ธฐ ์ ์ ๋ฎคํ
์ค๋ฅผ ํตํด Lock์ ๊ฑธ๊ณ , ์์์ ์ฌ์ฉํ ํ์ ์ ๊ธ ํด์ (Unlock) ์ํ๋ก ๋ง๋ญ๋๋ค.
์ด๋ฌํ ์ ๊ทผ ๋ฐฉ์์ผ๋ก ๋ฎคํ
์ค๋ฅผ ์ฌ์ฉํ๋ฉด ํ ๋ฒ์ ํ๋์ ์ค๋ ๋๋ง์ด ์์์ ์ ๊ทผํ๊ฒ ๋๋ฏ๋ก ๊ฒฝ์์ํ(Race Condition)๋ ๋ฐ๋๋ฝ(Deadlock) ๋ฑ์ ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
์กฐ๊ฑด๋ณ์(condition_variable)
std::condition_variable์ C++ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๊ธฐํ ๊ธฐ๋ฅ ์ค ํ๋๋ก, ์ค๋ ๋ ๊ฐ์ ์ํธ์์ฉ๊ณผ ๋๊ธฐํ๋ฅผ ์ํด ์ฌ์ฉ๋๋ ํด๋์ค์
๋๋ค. ์ฃผ๋ก ํน์ ์กฐ๊ฑด์ด ๋ง์กฑ๋ ๋๊น์ง ์ค๋ ๋์ ๋๊ธฐ(wait) ๋ฐ ํต์ง(notify) ๊ธฐ๋ฅ์ ์ ๊ณตํ์ฌ ์ค๋ ๋๋ค์ด ํจ์จ์ ์ผ๋ก ํ๋ ฅํ๊ณ ์กฐ์ ํ ์ ์๊ฒ ํด์ค๋๋ค.
std::condition_variable์ ์ฌ์ฉํ๋ฉด ์ค๋ ๋๊ฐ ํน์ ์กฐ๊ฑด์ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ๋๊ธฐํ๋ ๋์, ๋ค๋ฅธ ์ค๋ ๋๊ฐ ๊ทธ ์กฐ๊ฑด์ด ๋ง์กฑ๋๋ฉด ๋๊ธฐ ์ค์ธ ์ค๋ ๋๋ฅผ ๊นจ์ฐ๊ณ ํต์งํ ์ ์์ต๋๋ค. ์ด๋ ์ค๋ ๋ ๊ฐ์ ํจ์จ์ ์ธ ์์
๋ถ๋ฐฐ์ ํ๋ ฅ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
std::condition_variable์ ์ฌ์ฉํ๋ ค๋ฉด ์ฃผ๋ก ๋ ๊ฐ์ง ๋์์ ์ํํฉ๋๋ค:
1. ๋๊ธฐ(wait)ํ๊ธฐ: ์ค๋ ๋๊ฐ ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ ๋๊น์ง ๋๊ธฐํ๋ ์ํ๋ก ๋ค์ด๊ฐ๋๋ค. std::condition_variable ๊ฐ์ฒด์ ํจ๊ป std::unique_lock์ ์ฌ์ฉํ์ฌ ๋ฎคํ
์ค์ ์ฐ๊ณํ์ฌ ๋๊ธฐ ์ํ๋ก ๋ค์ด๊ฐ๋๋ค.
2. ํต์ง(notify)ํ๊ธฐ: ํน์ ์กฐ๊ฑด์ด ๋ง์กฑ๋์์ ๋, ๋ค๋ฅธ ์ค๋ ๋๋ฅผ ๋๊ธฐ ์ํ์์ ๊นจ์ฐ๊ณ ์์
์ ๊ณ์ํ๋๋ก ํฉ๋๋ค. notify_one ๋๋ notify_all ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋๊ธฐ ์ค์ธ ์ค๋ ๋๋ฅผ ๊นจ์ธ ์ ์์ต๋๋ค.
์๋๋ std::condition_variable์ ์ฌ์ฉํ ๊ฐ๋จํ ์์ ์ฝ๋์
๋๋ค:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void workerThread() {
std::this_thread::sleep_for(std::chrono::seconds(2));
{
std::unique_lock<std::mutex> lock(mtx);
ready = true;
std::cout << "Worker thread is ready." << std::endl;
}
cv.notify_one();
}
int main() {
std::thread t(workerThread);
{
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return ready; });
std::cout << "Main thread received notification." << std::endl;
}
t.join();
return 0;
}
์ด ์์ ์์ workerThread๋ 2์ด ํ์ ready ๋ณ์๋ฅผ true๋ก ์ค์ ํ๊ณ , cv.notify_one()์ ํธ์ถํ์ฌ ๋๊ธฐ ์ค์ธ ์ค๋ ๋๋ฅผ ๊นจ์ฐ๋ ์ญํ ์ ํฉ๋๋ค. main ํจ์์์๋ cv.wait()์ ํธ์ถํ์ฌ ready ๋ณ์์ ๋ณ๊ฒฝ์ ๊ธฐ๋ค๋ฆฐ ํ ํต์ง๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํฉ๋๋ค.
์๋๋ condition_variable์ wait_for(๋๊ธฐ ์๊ฐ ์ง์ )๋ฅผ ์ฌ์ฉํ ์์ ์ ๋๋ค.
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void workerThread() {
std::this_thread::sleep_for(std::chrono::seconds(2));
{
std::unique_lock<std::mutex> lock(mtx);
ready = true;
std::cout << "Worker thread is ready." << std::endl;
}
cv.notify_one();
}
int main() {
std::thread t(workerThread);
{
std::unique_lock<std::mutex> lock(mtx);
if (cv.wait_for(lock, std::chrono::seconds(1), [] { return ready; })) {
std::cout << "Main thread received notification." << std::endl;
} else {
std::cout << "Main thread timed out waiting for notification." << std::endl;
}
}
t.join();
return 0;
}
cv.wait_for() ํจ์๋ ๋๊ธฐ ์ค์ธ ์ค๋ ๋๊ฐ ready ๋ณ์๊ฐ true๋ก ๋ณ๊ฒฝ๋๊ฑฐ๋ ์ต๋ 1์ด๊ฐ ๊ฒฝ๊ณผํ ๋๊น์ง ๋๊ธฐํฉ๋๋ค. ๊ฒฝ๊ณผํ ์๊ฐ์ด ๋๊ธฐ ์๊ฐ์ ์ด๊ณผํ๋ฉด cv.wait_for()๋ false๋ฅผ ๋ฐํํ๊ณ , ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ์๋ true๋ฅผ ๋ฐํํ๋ฉด์ ๋๊ธฐ ์ค์ธ ์ค๋ ๋๋ฅผ ๊นจ์ฐ๊ฒ ๋ฉ๋๋ค.
std::async
std::async๋ C++ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ ๊ณตํ๋ ๋น๋๊ธฐ ์์
์ ์์ฑํ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ํ ํจ์์
๋๋ค. ์ด๋ฅผ ํตํด ํจ์๋ ํจ์ ๊ฐ์ฒด๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ์คํํ๋ฉฐ, ๋ณ๋์ ์ค๋ ๋์์ ์์
์ ์ฒ๋ฆฌํ๊ฑฐ๋ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ์คํํ ์ ์์ต๋๋ค. std::async๋ ๊ฐ๋จํ ๋น๋๊ธฐ ์์
์ ์ฒ๋ฆฌํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ๋ฐ์ ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค.
std::async ํจ์์ ๊ธฐ๋ณธ ํ์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
template <class Function, class... Args>
std::future<typename std::result_of<Function(Args...)>::type>
std::async(std::launch policy, Function&& f, Args&&... args);
std::async ํจ์๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. std::launch ์ด๊ฑฐํ์ ์ด์ฉํ์ฌ ์คํ ์ ์ฑ
์ ์ง์ ํฉ๋๋ค. ์ฃผ๋ก std::launch::async๋ std::launch::deferred๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- std::launch::async: ์๋ก์ด ์ค๋ ๋์์ ๋น๋๊ธฐ ์์
์ ์คํํฉ๋๋ค.
- std::launch::deferred: ์์
์ ํธ์ถํ์ง ์๊ณ ๊ฒฐ๊ณผ๋ฅผ ์์ฒญํ ๋๊น์ง ์ง์ฐ์ํต๋๋ค.
2. ๋น๋๊ธฐ๋ก ์คํํ ํจ์๋ ํจ์ ๊ฐ์ฒด๋ฅผ ์ ๋ฌํฉ๋๋ค.
3. ํจ์์ ํ์ํ ์ธ์๋ค์ ์ ๋ฌํฉ๋๋ค.
std::async๋ ๋ฐํ๊ฐ์ผ๋ก std::future ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋๋ฐ, ์ด ๊ฐ์ฒด๋ฅผ ํตํด ๋น๋๊ธฐ ์์
์ ์ํ๋ฅผ ํ์ธํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค.
๊ฐ๋จํ ์์ ์ฝ๋๋ฅผ ํตํด std::async๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ๋๋ฆฌ๊ฒ ์ต๋๋ค.
#include <iostream>
#include <future>
int add(int a, int b) {
return a + b;
}
int main() {
// ๋น๋๊ธฐ ์์
์ ์คํํ๊ณ ๊ฒฐ๊ณผ๋ฅผ std::future๋ก ๋ฐ์
std::future<int> result = std::async(std::launch::async, add, 3, 5);
// ๊ฒฐ๊ณผ๋ฅผ ์ป๊ธฐ ์ํด wait ๋ฐ get์ ์ฌ์ฉ
result.wait();
int sum = result.get();
std::cout << "Sum: " << sum << std::endl;
return 0;
}
std::async๋ฅผ ์ฌ์ฉํ์ฌ add ํจ์๋ฅผ ๋น๋๊ธฐ์ ์ผ๋ก ์คํํ๊ณ , ๊ฒฐ๊ณผ๋ฅผ ์ป๊ธฐ ์ํด std::future์ wait์ get ํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. std::launch::async๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ก์ด ์ค๋ ๋์์ ์์
์ ์คํํ๊ฒ ๋ฉ๋๋ค.
์ข๋ ๋ณต์กํ ์์ ๋ฅผ ๋ณด์์ฃ .
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <future>
int parallelSum(const std::vector<int>& data, size_t chunkSize) {
std::vector<std::future<int>> futures;
// ๋ฒกํฐ๋ฅผ chunkSize๋งํผ ๋๋์ด ๋ณ๋ ฌ๋ก ํฉ์ฐ ์์
์ํ
for (size_t i = 0; i < data.size(); i += chunkSize) {
auto chunkBegin = data.begin() + i;
auto chunkEnd = chunkBegin + chunkSize;
futures.push_back(std::async(std::launch::async,
[](std::vector<int>::const_iterator begin, std::vector<int>::const_iterator end) {
return std::accumulate(begin, end, 0);
},
chunkBegin, chunkEnd));
}
// ๊ฐ๋ณ ์์
๊ฒฐ๊ณผ๋ฅผ ๋ชจ๋ ํฉ์ฐ
int totalSum = 0;
for (auto& future : futures) {
totalSum += future.get();
}
return totalSum;
}
int main() {
std::vector<int> data(10000);
std::iota(data.begin(), data.end(), 1); // 1๋ถํฐ 10000๊น์ง์ ์๋ก ์ฑ์
const size_t chunkSize = 1000;
int sum = parallelSum(data, chunkSize);
std::cout << "Parallel Sum: " << sum << std::endl;
return 0;
}
๋ฒกํฐ์ ์์๋ค์ ๋ณ๋ ฌ๋ก ํฉ์ฐํ๋ ์์ ์ ๋๋ค. ๋ฒกํฐ๋ฅผ ์ฌ๋ฌ ๊ฐ์ ์ฒญํฌ(chunk)๋ก ๋๋์ด ๊ฐ ์ฒญํฌ๋ฅผ ๋ณ๋์ ์ค๋ ๋์์ ํฉ์ฐํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ๋ ํฉ์ฐํ์ฌ ๋ณ๋ ฌ ํฉ์ฐ์ ์ํํฉ๋๋ค. ๊ฐ ์ฒญํฌ๋ฅผ ๋ณ๋์ std::async ์์ ์ผ๋ก ์คํํ๋ฉฐ, std::accumulate๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ ์ฒญํฌ์ ํฉ์ ๊ณ์ฐํฉ๋๋ค. ๋ง์ง๋ง์ผ๋ก ๋ชจ๋ ์์ ์ ๊ฒฐ๊ณผ๋ฅผ ํฉ์ฐํ์ฌ ์ต์ข ๊ฒฐ๊ณผ๋ฅผ ์ป์ต๋๋ค.
std::async๋ ์์ (task)๊ธฐ๋ฐ ์ ๊ทผ์ด๋ฉฐ std::thread๋ ์ค๋ ๋(thread)๊ธฐ๋ฐ ์ ๊ทผ ๋ฐฉ์์ ๋๋ค. ์ ๊ฐ์ ๊ฒฝ์ฐ, ๋ฒ์ฉ์ ์ธ ๊ฒฝ์ฐ์๋ std::async๋ฅผ ์ฌ์ฉํ๋ฉฐ, ์ค๋ ๋์ ์์ ์ ํน์ํ๊ณ ์ธ์ธํ๊ฒ ์กฐ์ ํ๊ฑฐ๋ ์ค๋ ๋ํ์ ๋ง๋ค ๊ฒฝ์ฐ์๋ std::thread๋ฅผ ์ฌ์ฉํฉ๋๋ค.
Effective c++์์๋ std::async๋ฅผ ๊ถ์ฅํฉ๋๋ค. ๊ทธ ์ด์ ๋, std::async๋ OS ๋ด๋ถ์์ Thread Pool์ ๋ง๋ค์ด ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋ง์ ๋ฆฌ์์ค๋ฅผ ์๊ตฌํ์ง ์์ต๋๋ค. ๋ํ thread์ ๋ฌ๋ฆฌ return๊ฐ์ด ์์ด์ ์ด๋ฅผ ํ์ฉํ ์ ์๋ค๋ ์ ๊ณผ ์์ธ์ฒ๋ฆฌ๊ฐ ๋ ํจ์จ์ ์ด๋ผ๋ ๊ฒ์ด ์ฅ์ ์ ๋๋ค.
๋ง๋ฌด๋ฆฌ
ํ์ ์์๋ ๋ชจ๋ C++๋ก ๊ตฌ์ฑ๋ ์๋ฒ ํ๋ก๊ทธ๋จ & ๋ฐ๋ชฌ ํ๋ก๊ทธ๋จ์ ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์ ๋๋ค. ๋ฉํฐ์ค๋ ๋๋ฅผ ์ดํดํ๊ณ ๋ค๋ฃฐ ์ ์๋ ๋ฅ๋ ฅ์ด ๊ณ ๊ธ ๊ฐ๋ฐ์๋ก ๊ฐ๊ธฐ ์ํ ํ๋ณ ์ค ํ๋์ ๋๋ค. ๋ฉํฐ์ค๋ ๋ ํ๋ก๊ทธ๋๋ฐ์ ๋๋ฒ๊น ๋ ์ฝ์ง ์์ผ๋ฉฐ ์ง๊ด์ ์ด์ง ์๊ธฐ ๋๋ฌธ์ ์ฝ๋๋ฅผ ์์ฑํ๋๋ผ๋ ์ด๋ป๊ฒ ํ๋ฌ๊ฐ๋์ง ์ดํดํ๊ธฐ ์ฝ์ง ์์ต๋๋ค. ๊ฐ๊ฐ์ ์ค๋ ๋์ ๋์๊ณผ ๊ณต์ ์์ ๊ด๋ฆฌ, ์ค๋ ๋๋ผ๋ฆฌ์ ์ถฉ๋์ํฉ ๋ฑ์ ์ด์์ฒด์ ์ ๋ฉ๋ชจ๋ฆฌ ๊ด์ ์์ ์ดํดํ๋ ค๊ณ ๋ ธ๋ ฅํด์ผ ํฉ๋๋ค.
๋ฉํฐ์ค๋ ๋๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋ ๋๋ถ๋ถ ๋ณ๋ ฌ์ฒ๋ฆฌ๋ฅผ ํ๊ธฐ ์ํจ์ ๋๋ค. ํ๊บผ๋ฒ์ ๋ง์ ์์ ์ด๋ฒคํธ or ์์ ์ด ์์ ๋ ์ฌ๋ฌ ๊ฐ์ ์ค๋ ๋์๊ฒ ๋ณ๋์ ์์ ์ฒ๋ฆฌ๋ฅผ ๋งก๊น๋๋ค. ๋ง์ฝ ์ค๋ ๋๋ผ๋ฆฌ ๊ณต์ ํด์ผ ํ๋ ์์์ด ์์ ๊ฒฝ์ฐ ์ ์ ํ ์์น์ mutex lock์ ์ฌ์ฉํ์ฌ ์์์ ๋ ์ ๊ถ์ ๊ฐ์ง๋๋ก ํฉ๋๋ค. mutex lock์ผ๋ก ์ค๋ ๋๊ฐ ์์์ ์ ์ ํ๋ ์๊ฐ์ด ์งง์ ์๋ก ์ฒ๋ฆฌ์๋๋ ์ฆ๊ฐํฉ๋๋ค. ๋ฌผ๋ก lock์ ์์ฐ๋ ๊ฒ์ด ์ ์ผ ์ข๊ฒ ์ฃ .
์ฌ๋ฌ ๊ฐ์ ์ค๋ ๋์๊ฒ ์์ ์ฒ๋ฆฌ๋ฅผ ๋งก๊ธธ ๋ condition_variable์ notify()๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ค๋ ๋๋ค์ ์์ ์ด ์์ ๋ wait์ํ๋ก ๋๊ธฐํ๊ณ ์๋ค๊ฐ ์์ ์ด ๋ชฐ๋ ธ์ ๋, notify()๋ฅผ ํตํด wait์ํ์์ ๋ฒ์ด๋๊ณ ์ ํด์ง ๋ก์ง์ ์ํํ๊ณ ๋ค์ wait์ํ๋ก ๋์๊ฐ๋ ํ๋ก์ธ์ค๊ฐ ์ผ๋ฐ์ ์ ๋๋ค.
๋ค์ ํฌ์คํ ์ ๋์ฌ "ํ๋ก๋์ ์ปจ์๋จธ ํจํด"๊ณผ "์ค๋ ๋ํ"์์ ๋ชจ๋ ๊ณผ์ ์ ์์ ๋ฅผ ๋ณผ ์ ์์ต๋๋ค.
'ํ๋ก๊ทธ๋๋ฐ ์ธ์ด > C++ ๊ธฐ์ด' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[C++] 22. ์ค๋ ๋ ํ(Thread Pool), ์์ฐ์ ์๋น์ ํจํด(Producer-consumer) (0) | 2023.09.04 |
---|---|
[C++] 20. ๋ฉํฐ ์ค๋ ๋ ํ๋ก๊ทธ๋๋ฐ(Multi-Threads) (0) | 2023.08.18 |
[C++] 19. ์ฐ์ฐ์ ์ค๋ฒ๋ก๋ฉ(Operator Overloading) (0) | 2023.08.07 |
[C++] 18. Standard Library ์ ๋ณตํ๊ธฐ(STL) (0) | 2023.08.06 |
[C++] 17. ์์ธ์ฒ๋ฆฌ(Exception), std::exception (0) | 2023.07.23 |
๋๊ธ