프로세스는 운영체제에서 실행되는 프로그램의 최소단위
프로세스는 cpu의 코어에서 실행이 된다.
CPU 코어에서 돌아가는 프로그램 단위이다.
CPU 한개의 코어에서 한 번에 한 개의 쓰레드의 명령을 실행시킨다.
한개의 프로세스는 최소 한 개의 쓰레드로 이루어짐
두 개 이상의 쓰레드는 멀티쓰레드라고 부른다.
프로세스는 메모리를 서로 공유하지 않는다. 즉 프로세스1 과 프로세스2는 서로의 메모리에 접근할 수 없다.
반면에, 같은 프로세스 내에 있는 쓰레드는 서로 메모리를 공유한다. 만약 프로세스1에 쓰레드1, 쓰레드2, 쓰레드3이 있다면 이 세개는 서로 메모리를 공유하는 것이다.
병렬가능한 작업을 처리할 때 매우 효율적이기 때문이다.
EX) 만약 for문으로 i = 1 부터 1000까지 계산해야 하는 작업이 있고 덧셈당 1초가 걸린다고 하자. 만약 싱글 쓰레드로 작업을 수행하면 1000초가 걸리게 될 것이다.
하지만 이것을 10개의 쓰레드로 나누어 i = 1 부터 100/ 101부터 200 / 201부터 300/.....이런 식으로 할 경우 총 110초가 걸릴 것이다.(10초는 마지막에 각각의 쓰레드에서 나온 값을 합치는데 걸리는시간) 대략 10배 더 빠르게 작업을 수행 할 수 있는 것이다.
이때 병렬 가능한 작업을 처리할 때가 중요한 조건이다.
만약 전에 계산한 값이 다음 값에 영향을 주는(dependent,데이터 의존)일 경우 병렬적이기 어렵게 된다.
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <math.h>
#include <set>
#include <map>
#include <deque>
#include <thread>
using namespace std;
using std::thread;
void func1()
{
for (int i = 0; i < 4; i++)
{
cout << "쓰레드1 작동중!\n";
}
}
void func2()
{
for (int i = 0; i < 4; i++)
{
cout << "쓰레드2 작동중!\n";
}
}
void func3()
{
for (int i = 0; i < 4; i++)
{
cout << "쓰레드3 작동중!\n";
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
thread t1(func1);
thread t2(func2);
thread t3(func3);
t1.join();
t2.join();
t3.join();
return 0;
}
#include <thread>
thread헤더 파일 추가
이후 thread객체를 생성해주고 그 안에 func함수를 인자로 전달해준다.
즉 예시 코드에서는 서로 다른 세 개의 쓰레드에서 각각 함수를 실행하게 된다.
thread.join()함수는 해당하는 쓰레드들이 종료하면 리턴하는 함수이다.
만약 이것을 설정하지 않는다면 main함수가 먼저 종료를 해버리게 되어 thread객체의 소멸자가 호출되게 된다.
->예외가 발생하게 됨..
비슷한 함수로 .detach()도 존재하는데 main과 독립적으로 만든다(잊어버린다)고 생각하면 된다. 백그라운드에서 계속 돌아감.
#결과

결과를 보면 쓰레드 작동 순서가 뒤죽박죽인 것을 알 수 있다.
이것은 운영체제에서 어떤 코어에 할당하고 어떤 순서로 스케줄할지는 상황에 따라 달라지기 때문이다.
1부터 10000까지의 합을 멀티쓰레드를 통해 구해보기
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>
#include <math.h>
#include <set>
#include <map>
#include <deque>
#include <thread>
using namespace std;
using std::thread;
void worker(vector<int>::iterator start, vector<int>::iterator end,
int *result)
{
int sum = 0;
for (auto iter = start; iter != end; iter++)
{
sum += (*iter);
}
*result = sum;
thread::id this_id = this_thread::get_id(); //현재 쓰레드의 주소? id 가져오기
printf("쓰레드 %x에서 %d부터 %d까지 계산한 결과: %d \n", this_id, *start, *(end - 1), sum);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
vector<int> nums(10000);
for (int i = 0; i < 10000; i++)
{
nums[i] = i;
}
vector <int>partial_sums(4); //각 쓰레드에서 구해온 합들..
vector<thread> workers;
for (int i = 0; i < 4; i++)
{
workers.push_back(thread(worker, nums.begin() + i * 2500
, nums.begin() + (i + 1) * 2500, &partial_sums[i]));
}
for (int i = 0; i < 4; i++)
{
workers[i].join();
}
int total = 0;
for (int i = 0; i < 4; i++)
{
total += partial_sums[i];
}
cout << "전체 합은 " << total;
return 0;
}
쓰레드에는 반환값이 없기에 값을 저장하고 싶다면 포인터으 형태로 전달하기.
쓰레드 인자 전달할 때 함수를 전달할 경우 bind처럼 함수 다음에는 그 함수의 인자를 순서대로 전달하기
printf를 쓴 이유 cout을 쓸 경우 cout << 쓰레드 << id ...이런 형태에서 쓰레드까지만 실행을 했는데 다음 쓰레드로 넘어갈 수 있기에 방해 받지 않고 전체메시지를 출력하기 위해서
#결과

<출처>
모두의 코드