비동기 방식의 필요성.
•멀티 스레드 프로그래밍은 기본(코어가 여러 개니까.)
• 하나의 프로그램이 이제 네트워크로 연결된 별도의 프로세서에
서 동작하는 경우도 너무 많다(쓸 만한 서비스는 거의 대부분).
• 락을 이용한 동기화 방식으로 멀티 스레드 프로그램을 만든다
는 건, 결국 어느 시점에서는 다른 스레드를 기다리기 위해 블럭
상태에 있어야 한다는 거다.
• 결국 성능향상을 위해서 멀티 스레드 프로그램을 만들었는데
그 노력이 허사가 돼 버린다.
• 결국 비동기 방식의 멀티 스레드 프로그램을 만들어야 한다.
Appendix : std::future,std::promise(2)
•std::promis<dataType> promis1; //promis객체를 생성하고
• auto future1 = promis1.get_future();//promis1에 해당하는 future객체를 받고.
• std::thread th1(
[&promis1, inFile](){ promis1.set_value(readFile(inFile));}
);// 값을 생산하는 스레드에 promis1을 전달하고 값을 promis1에 저장한다
• size_t result = fut2.get();
//원래 스레드에서는 다른 작업을 하다가. 값이 필요할 때 future1객체를 이용해서 값을 받을 수 있다. 이때 블럭이 된다.
5.
Appendix : std::async
•하지만 위의 std::future와 std::promis는 사용하기 불편하다.
• 코드도 복잡하고.
• 그때 사용할 수 있는 것이 std::async
• 처음인자로 함수자나 람다를 넣고 그 다음 그 함수자나 람다의
인자를 순서대로 매개 변수에 넣어 주면 그 리턴 값의
std::future 객체를 반환한다.
• 스레드도 알아서 만들어 준다(많이 추상화 되어있음.)
예제 코드: 소수구하기
• 소수를 구하는 함수들.
https://gist.github.com/LethalSun/d74cfe458196eb23518242c33
2fc6597
• 정수 범위가 주어 졌을 때 스레드 마다 범위를 나눠주는 함수.
https://gist.github.com/LethalSun/2131d3601f7431a4810b8defd
d3efb1e
• 실제 스레드를 만들어서 테스트 하는 코드.
https://gist.github.com/LethalSun/3b6452d4dd0514f9e8b4e7e0
e4d4c2e3
8.
비동기 방식에서의 std::vector
•멀티 스레드 간에 공유를 하는 경우
->이상하게 동작한다.
• 동기화 객체를 이용해서 락을 거는 경우
-> 잘 동작하지만 여러 개의 스레드를 사용한 것에 비해서 싱글
스레드로 하는 것과 차이가 없다…
• PPL 병렬 컨테이너를 사용했을 때.
->잘 동작한다. 동기화같은걸 고민하지 않았는데…
9.
비동기 방식에서의 std::vector(2)
•동기화 객체를 이용하지 않았을 때 문제가 발생한 이유.
• 각각의 스레드가 이터레이터를 이용해서 공유 컨테이너의 값을 읽고
있을 때 다른 스레드에서 컨테이너의 값을 삭제 하거나 이동하면 이터
레이터는 무효가 된다.
• 또 값을 추가 할 때 현재 컨테이너가 수용할 수 있는 개수를 초과 하면
새로운 공간에 가지고 있는 요소를 전부 복사하게 되는데 이때 그냥 동
일한 공간다음의 위치를 추가적으로 확보하는게 아니라 새로운 공간에
새로운 크기만큼 할당하게 된다(아마 물리적 공간에서의 연속성을 가
져야 하기 때문이 아닐까?)
• 즉 삭제 뿐만 아니라, 삽입도 문제가 된다…
10.
Microsoft PPL(Parallel PatternsLibrary)
• 이러한 컨테이너의 문제점을 해결하기위해서 마이크로 소프트
에서 만든 PPL컨테이너가 존재함.
• concurrent_vector
• concurrent_que
• concurrent_unordered_map
• concurrent_unordered_multimap
• concurrent_unordered_set
• concurrent_unordered_multiset
• Linux 에서는 Intel TBB:Threading Building Blocks이 존재한다.
• 추가로concurrent_bounded_queue/concurrent_priority_queue도 지원
예)concurrency::concurrent_vector (cont.)
• 당연히락을 사용하지 않고 동시에 접근해서 조작 가능하다.
• 끝에 요소를 넣는 push_back으로만 요소를 넣어야 한다.
• Push_back에 move시멘틱을 지원하지 않는다.
• erase, pop_back이 없고 전체를 지우는 clear는 동시실행을 지
원하지 않는다->요소의 삭제는 동시 실행이 불가능 하다.
• 각 요소는 메모리 상에 연속적으로 존재하지 않는다.
• 하지만 배열처럼 임의 접근은 가능하다.
• 요소를 추가하거나 벡터를 확장할 때 요소를 재배치 하지 않는
다.
예)concurrency::concurrent_queue (cont.)
• push(Enqueue)와 try_pop(Dequeue)은 동시 실행 가능하다.
• front 와 pop메소드는 없다.
• 이터레이터를 사용할 수 있지만 동시 실행 가능하지 않다.
• Back메소드는 존재하지 않고 끝 값을 참조할 수도 없다.
• size메소드 대신 동시 실행 가능하지 않은 unsafe_size메소드를
제공한다.
• clear와 empty로 concurrent_que를 비울 수 있지만 empty만 동
시실행 가능하다.