1. 메모리의 Access 비용
1.1 역시나 Register 메모리가 제일 빠르다. Register 메모리는 1cycle.
1.2 L1, L2 . L1 > L2
1.3 Memory 50-300
1.4 Disk access cost 1-15ms
1.5 Network Disk 100ms-10Sec
요약 : 가장 빠른 것은 레지스터, L1, L2 순서지만 L2와 메모리의 속도차이는 아주 많다.
2. 보통 쓰레드를 생성할 때는 _beginthreadex 를 사용하는 게 좋다.
(일반 프로그램이니까 이게 게임에도 들어갈 듯)
MFC를 사용하는 UI 응용 프로그램은 AfxBeginThread
WindowOS에서는 CreateThread() 를 사용하자. ...지만, 이건 Window Os에 종속적인 놈이라 좀 꺼림칙할 듯 함.
3. 쓰레드마다 서로 다른 메모리 영역을 사용하나?
Thread Local Storage를 이용한다. 많은 수의 TLS를 사용하지 않는 게 좋다
3.1 Thread Stack Size
많은 수의 Thread를 사용하려면 Thread Staack Size를 조정해야 한다.
Ex) HANDLE h = CreateThread(NULL, 4096, ThreadProc, NULL, STACK_SIZE_PARAM_IS_A_RESERVATION, &id);
3.2 Thread를 최소한으로 만든다.
1프로세서당 1개의 스레드를 만들고 작업은 큐를 이용해서 순차적으로 처리하게 스레드를 생성해야 한다.
3.3 대용량 멀티 스레드 프로그램을 개발할 때는 Thread Pool을 이용해서 개발하는 게 좋을 것임.
4. Thread 종료
4.1 Thread 함수가 return 또는 ExitThread를 호출할 때
종료되는 Thread의 Stack이 제거되고 초기화된 모든 Pending I/O가 취소된다.
4.2 Closehandle을 꼭 수행해 주도록 한다.
4.3 TerminateThread API는 최대한 사용하지 않는 게 좋다.
-좀 위험함
그럼 어케 종료할 꺼냐? 바로 이벤트 오브젝트를 이용하는 것이다!
1. 이벤트 오브젝트 생성
2. 쓰레드 생서
3. WaitForSingleObject로 timeout 시간 설정을 0으로 해서 감시
4. Thread에서 감시중인 이벤트 오브젝트에 시그널 되면 종료시키자.
5. thread동기화
EnterCriticalSection의 API를 MSDN에서 확인해 보면 리턴값이 VOID형이다.
시스템에 메모리가 부족할 때 EnterCriticalSection 함수 호출한 곳에서 Exception이 발생한다.
5.1 그럼 어케 해야 하느냐?
Structured Execetpion handling을 이용한다. 그래 그거. try catch
initializeCriticalSection 초기화 함수 대신
InitializeCriticalSectionAndSpinCount를 사용한다.
스핀카운트는 다중 프로세서 시스템에서 여러 프로그램이 동시에 같은 리소스를 액세스해야 할 때 성능을 높이기 위한 방법이다. 스핀카운트는 프로세서가 기다리기 전에 리소스를 액세스하기 위해 시도하는 횟수를 말함.
5.2 Vista에서 CriticalSection이 보안 때문에 수정되었다. 이건 나중에.
6. Thread 동기화(Synchronization)
6.1세마포어(Semaphore) 오브젝트 사용하기
CreateSemaphore()
하나의 동기화 객체를 기다리는 Thread가 너무 많은 경우 세마포어를 하나 더 둬서 새당 동기화 객체를 기다리는 Thread 숫자를 줄여주는 것이 성능향상에 도움이 된다.
6.2 이벤트 오브젝트 사용하기
기본적인 것은 알고 있으니까 넘어가고
10개의 Thread가 동일한 이벤트 오브젝트를 기다리고 있을 경우?
SetEvent() : Signal로 전환. 이건 아는 것이니까 넘어가고
PulseEvent() : Signaled로 갔다가 바로 non-Signaled로 전환. Manual reset Event이면 대기 중이던 스레드가 전부 깨어나고 auto reset이면 한 개만 꺠어난다.
6.3. WaitForMultipleObjects API 사용하기
6.3.1
두 개 이상의 이벤트가 동시에 시그널 상태가 될 수 있다.(호.. 이런 경우는 생각안해봤는데)
6.3.2 하나의 이벤트가 두 번 이상 시그널 될 수 있다.
이건 코딩을 잘 못한 것이다. 이벤트 오브젝트가 완료된 이후에 재사용하도록 코드를 작성했다면 하나의 이벤트에 두 번 이상 시그널 되지 않는다.
6.3.3 비동기 이벤트이므로 실행 순서를 보장받지 않는다.
이건 나중에 버그로 발견되기가 쉽지 않으므로 주의하고 있어야 함.
7. STL/MFC Collection을 사용할 때는?
-여러 Thread에서 읽는 것은 안전
-각각 다른 컨테이너를 쓰는 것은 안전
단. 삽입 삭제, 조회를 하는 모든 경우에는 동기화 필요
반복자를 수행하는 것도 전부 동기화가 필요
8. 그 외 주의점.
8.1 사용하는 운영체제와 CPU 특성을 알고 있어야 한다.
Window200 Professional과 Server는 Thread Quantum값이 다르다.
8.2 메모리 조각화가 발생하지 않도록 해야 한다.
8.3 최대한 if문 사용을 자제한다.
8.4 4가지 동기화 객체 특징을 알고 있어야 한다.
mutex, Semaphore, Event, CriticalSection.
8.5 리스트에서 빈번한 추가 삭제가 일어난다면 아예 배열을 사용하셈.
8.6 포인터를 사용하지 않는다. ..사용하게 된다면 스마트 포인트를 사용한다.
8.7 한 번 할당한 메모리 포인터는 삭제하지 않고 재사용하게 클래스를 설계할 것.
8.8 메모리 삭제 생성을 빈번하게 해야 한다면 메모리 풀을 이용한다.
9. 쓰레드가 너무 많으면?
디버깅이 힘들다. 당근.
동기화 오브젝트는 64개가 한계. 그 외는 사용자가 직접 동기화를 해야 한다.
쓰레드 수에 비례해서 switching의 빈도수와 부하가 커진다.
100이라는 양을 2번 처리해야 하는 경우 한 개의 Thread에서 100을 두번 처리하는 것 보다 두 개의 Thread에서 100을 각각 하나씩 동시에 처리하는 경우 더 시간이 걸린다.
10. Thread Pool
Thread Pool은 천하무적이 아님. 우리한테 꼭 필요한 것인가를 먼저 검토한 다음에 사용여부를 결정해야 한다.
- 분산 처리가 안된다
- 사용자당 처리 응답 시간이 긴 경우가 많다
---이것은 1월6일의 세미나 PT를 정리한 것입니다. 자세한 사항은
http://blog.naver.com/process3 이곳을 참고하면 좋습니다. ...새로운 것을 많이 알게 되었네요. PT및 발표 데모 자료는 위 홈페이지에서 받으실 수 있습니다.---
Posted by 휴리첼