|
|
| 기존의 C/C++의 경우 멀티스레드 프로그래밍을 하기 위해서는 운영체제API를 호출하거나 외부라이브러리(OpenMP)을 써야 했습니다. 이번 C++11에서는 표준라이브러리로 멀티스레드 지원을 위한 클래스가 추가되었습니다.
| |
|
| |
|
| thread헤더 파일를 포합시켜야 하며, 스레드의 진입함수에 매개 변수를 넣어 줄 수 있습니다.
| |
| std::thread(함수의 어드레스, 스레드의 진입점에 넣어줄 매개 변수...)
| |
| 매개 변수의 경우, printf함수 처럼 인자 수을 바꿀 수 도있습니다.
| |
|
| |
| 스레드를 쓴다음, 정리하기 위해서는 detach메소드나 join메소드를 호출 해줘야 합니다.
| |
|
| |
| 스레드를 잠시 쉬게 하는, 윈도우의 Sleep함수와 동일한 역할을 하는 함수는 std::this_thread::sleep_for(std::chrono::seconds(초))입니다.
| |
|
| |
| 다음 코드는 두 개의 1000x1000행렬을 곱하는 코드입니다.
| |
| <source lang="cpp">
| |
| #include <iostream>
| |
| #include <thread>
| |
| #include <mutex>
| |
| #include <windows.h>
| |
| #include <array>
| |
| #include <stdlib.h>
| |
| #include <time.h>
| |
| std::array<std::array<int,1000>,1000> a;
| |
| std::array<std::array<int,1000>,1000> b;
| |
| std::array<std::array<int,1000>,1000> c;
| |
| int main()
| |
| {
| |
|
| |
|
| |
| srand(time(NULL));
| |
| for(auto & i : a){
| |
| for(auto & j : i){
| |
| j = rand() % 5000;
| |
| }
| |
| }
| |
| for(auto & i : b){
| |
| for(auto & j : i){
| |
| j = rand() % 5000;
| |
| }
| |
| }
| |
| std::cout<<"시작!"<<std::endl;
| |
| int startTick = GetTickCount();
| |
| int endTick = 0;
| |
| for(int i = 0; i < c.size() ; i++)
| |
| {
| |
| for(int j = 0; j < c[i].size() ; j++)
| |
| {
| |
| for(int k = 0; k < c.size(); k++)
| |
| {
| |
|
| |
| c[i][j] += a[i][k] * b[k][j];
| |
| }
| |
| }
| |
| }
| |
| endTick = GetTickCount();
| |
| std::cout<<"끝! 걸린 시간 총 "<<double(endTick - startTick)/1000.0<<"초"<<std::endl;
| |
| return 0;
| |
| }
| |
|
| |
| </source>
| |
| 걸린 시간 50.875
| |
| == 멀티 스레드 베타1 ==
| |
| 가장 동기화 락에 덜걸리게 설계한다.
| |
| <source lang="cpp">
| |
| #include <iostream>
| |
| #include <thread>
| |
| #include <mutex>
| |
| #include <array>
| |
| #include <stdlib.h>
| |
| #include <time.h>
| |
| #include <queue>
| |
| #include <stdio.h>
| |
| #include <windows.h>
| |
| struct Node{
| |
| int i;
| |
| int j;
| |
| };
| |
| struct ResultWorkNode{
| |
| int i;
| |
| int j;
| |
| int r;
| |
| };
| |
|
| |
| std::mutex g_queueMutex;
| |
| std::mutex g_result;
| |
| std::queue<Node> g_workQueue;
| |
| std::queue<ResultWorkNode> g_resultQueue;
| |
|
| |
| std::array<std::array<int,1000>,1000> a;
| |
| std::array<std::array<int,1000>,1000> b;
| |
| std::array<std::array<int,1000>,1000> c;
| |
|
| |
| int thread_func(){
| |
| std::queue<Node> localQueue;
| |
| std::queue<ResultWorkNode> localResQueue;
| |
| while(g_workQueue.empty() == false){
| |
| //로컬 큐에 전역 큐에 있는 계산 해야 하는 것을 가져 온다.
| |
| if(localQueue.empty())
| |
| {
| |
| g_queueMutex.lock();
| |
| for(int i = 0 ; i < 5; i++){
| |
| if(g_workQueue.empty()){
| |
| break;
| |
| }
| |
| localQueue.push(g_workQueue.front());
| |
| g_workQueue.pop();
| |
| }
| |
| g_queueMutex.unlock();
| |
| }
| |
| else if(g_queueMutex.try_lock())
| |
| {
| |
| for(int i = 0 ; i < 5; i++){
| |
| if(g_workQueue.empty()){
| |
| break;
| |
| }
| |
| localQueue.push(g_workQueue.front());
| |
| g_workQueue.pop();
| |
| }
| |
| g_queueMutex.unlock();
| |
| }
| |
| //이제 로컬 큐에 있는 것을 계산한다.
| |
| while(localQueue.empty() == false){
| |
| Node node = localQueue.front();
| |
| localQueue.pop();
| |
| int res = 0;
| |
| for(int i = 0 ; i < 1000 ; i++){
| |
| res += a[node.i][i] * b[i][node.j];
| |
| }
| |
| //
| |
| ResultWorkNode r;
| |
| r.i = node.i;
| |
| r.j = node.j;
| |
| r.r = res;
| |
| //c[node.i][node.j] = res;
| |
| localResQueue.push(r);
| |
| }
| |
| if(g_result.try_lock()){
| |
| while(localQueue.empty() == false){
| |
| g_resultQueue.push(localResQueue.front());
| |
| localResQueue.pop();
| |
| }
| |
| g_result.unlock();
| |
| }
| |
|
| |
| }
| |
| if(localResQueue.empty() == false){
| |
| g_result.lock();
| |
| while(localResQueue.empty() == false){
| |
| g_resultQueue.push(localResQueue.front());
| |
| localResQueue.pop();
| |
| }
| |
| g_result.unlock();
| |
| }
| |
| return 0;
| |
| }
| |
|
| |
|
| |
|
| |
| int main()
| |
| {
| |
|
| |
|
| |
| srand(time(NULL));
| |
| for(int i = 0 ; i < 1000; i++){
| |
| for(int j = 0 ; j < 1000; j++){
| |
| a[i][j] = rand() % 10 + 1;
| |
| b[i][j] = rand() % 10 + 1;
| |
| }
| |
| }
| |
|
| |
| for(int i = 0; i < c.size() ; i++)
| |
| {
| |
| for(int j = 0; j < c[i].size() ; j++)
| |
| {
| |
| Node node;
| |
| node.i = i;
| |
| node.j = j;
| |
|
| |
| g_workQueue.push(node);
| |
| }
| |
| }
| |
|
| |
| std::cout<<"시작!"<<std::endl;
| |
| int startTick = GetTickCount();
| |
| int endTick = 0;
| |
| std::thread a(thread_func);
| |
| std::thread b(thread_func);
| |
| a.join();
| |
| b.join();
| |
| while(g_resultQueue.empty() == false){
| |
| ResultWorkNode n = g_resultQueue.front();
| |
| g_resultQueue.pop();
| |
| c[n.i][n.j] = n.r;
| |
| }
| |
|
| |
| endTick = GetTickCount();
| |
| FILE * fp = fopen("./res.txt","w+");
| |
| for(auto & i : c){
| |
| for(auto & cell : i){
| |
| fprintf(fp,"%7d ",cell);
| |
| }
| |
| fprintf(fp,"\n");
| |
| }
| |
| fclose(fp);
| |
| std::cout<<"끝! 걸린 시간 총 "<<double(endTick - startTick)/1000.0<<"초"<<std::endl;
| |
| return 0;
| |
| }
| |
| </source>
| |
|
| |
| 걸린 시간: 17초
| |
| TDM-GCC O2 최적화시 : 4초, 2차 실행시 CPU실행으로 인해 2초...
| |
| == 멀티 스레드 베타2 ==
| |