멀티 쓰레드 동기화(Syncronazation)
목차
//
org : http://msdn.microsoft.com/en-us/library/ms810428
Table 1. Synchronization Objects Summary
| Name | Relative speed | Cross process | Resource counting | Supported platforms | 
| Critical Section | Fast | No | No (Exclusive Access) | 95/NT/CE | 
| Mutex | Slow | Yes | No (Exclusive Access) | 95/NT/CE | 
| Semaphore | Slow | Yes | Yes | 95/NT | 
| Event | Slow | Yes | Yes* | 95/NT/CE | 
| Metered Section | Fast | Yes | Yes | 95/NT/CE | 
* Events can be used for resource counting, but they do not keep track of the count for you.
//
org : http://tiger5net.egloos.com/5537603
| object | Linux/Unix | Windows | 
| File Lock | kernel-mode | kernel-mode | 
| † Critical Section | 없음 | user-mode 한 프로세스 내에서만 사용가능 | 
| Interlock | 없음 | user-mode 한 프로세스 내에서만 사용가능 | 
| † Mutex | POSIX 함수 한 프로세스 내에서만 사용가능 하나의 공유자원 동기화에 사용 | kernel-mode 프로세스끼리도 사용가능 타임아웃기능 사용가능 하나의 공유자원 동기화에 사용 | 
| † Semaphore | kernel-mode POSIX 함수 프로세스끼리도 사용가능 다중 공유자원 동기화에 사용 | kernel-mode 프로세스끼리도 사용가능 타임아웃기능 사용가능 다중 공유자원 동기화에 사용 | 
| Condition Variable | POSIX 함수 타임아웃기능 사용가능 다중 스레드를 동시에 깨울 수 있음 | 없음 | 
| † Event | 없음 | kernel-mode 프로세스끼리도 사용가능 타임아웃기능 사용가능 다중 스레드나 프로세스를 동시에 깨울 수 있음 | 
//
- 
동기화(Syncronazation)#
http://en.wikipedia.org/wiki/Synchronization
    - 멀티프로그래밍(두개 이상의 쓰레드가 같은 
데이터를 공유하며 실행되고 있을때)에서
    에러(충돌,교착)가 발생하지 않고 조화롭게 실행되도록 하는 일련의 작업
    - 
이용되는 이론 : 세마포어(Semaphore), 임계구역(Critical Section), 스핀락(SpinLock), 상호배제(Mutual 
Exclusion, Mutex), 이벤트, Metered Section
- 
세마포어 (Semaphore) #
http://ko.wikipedia.org/wiki/%EC%84%B8%EB%A7%88%ED%8F%AC%EC%96%B4
    - 
멀티프로그래밍에서 공유자원에 대한 동시 접근을 제한하는 방법
    - 세마포어 S는 정수값을 가지는 변수이며, 다음과 같이 
P(test--)와 V(increment++)라는 명령에 의해서만 접근할 수 있다.
        P는 임계 구역에 들어가기 전에 
수행되고, V는 임계 구역에서 나올 때 수행된다
    - 세마포어는 임계구역을 다루기 위한 커널 객체다.(0이상의 정수)
    
CreateSemaphore : 세마포어 생성
    ReleaseSemaphore : 세마포어 카운트 증가
    
WaitForMultipleObjects : 세마포어 시그널을 기다림
    공유자원(임계구역)에 대한 접근을 하면 세마포어 카운트 
감소
    - 상태 : wait/ capture/  release
    - 카운트       
        
- 감소 : capture, 공유자원에 접근시
        - 증가 : release, ReleaseSemaphore()함수 
호출시
        - 0    : wait, 이면 공유자원에 대한 접근이 거부되지 않는다.
    - 동작 : 세마포어 
카운트가 증가(ReleaseSemaphore)하면,
        wait에 시그널이 가고(WaitForMultipleObjects), - 
임계구역 안에 위치
        공유자원(임계구역[EnterCriticalSection()-LeaveCriticalSection())의 
사용이 허용되면서
        세마포어 카운트 감소
- 
임계 구역( Critical section )#
http://ko.wikipedia.org/wiki/%EC%9E%84%EA%B3%84_%EA%B5%AC%EC%97%AD
    - 
동시 프로그래밍에서 공유 불가능한 자원의 동시 사용을 피하기 위해 사용되는 알고리즘
동시에 둘 이상의 스레드가 동시에 접근해서는 안되는 
공유 자원(자료 구조 또는 장치)을 접근하는 코드의 일부를 말한다.
임계 구역은 주로 지정된 시간이 지난 후 사라진다. 그래서 어떤 
스레드(작업 또는 프로세스)가 임계 구역에 들어가려면 지정된 시간을 기다려야 한다.
세마포어와 같이, 배타적인 사용을 보장하기 위해서는 
임계영역의 입장과 퇴장에는 어떤 동기화 기작이 필요하다.
    - InitializeCriticalSection : 임계구역 
초기화
    - DeleteCriticalSection : 임계구역 삭제
    - EnterCriticalSection : 
임계구역 진입, Lock
    - LeaveCriticalSection : 임계구역 떠남, Release
- 
스핀락(SpinLock)#
임계구역에 진입이 불가능할때 잠시 루프를 돌면서 재시도 하는 것(스핀)
    - 커널프로그래밍에서는 특히 가능한한 짧은 시간내에 
처리를 완료해야한다. MS 에서는 처리시간을 25마이크로초 이하로 하도록 권장한다.
크리티컬 섹션에 진입하기 전에 커널은 보호된 DPC 
큐와 관련된 스핀락을 획득해야 한다.
스핀락 획득에 실 패하면 성공할 때까지 계속 시도한다.
스핀락이란 이름은 락을 획득할 때까지 
커널(즉, 프로세스)는 계속해서 빙빙 돌고 있다(spinning)는데서 왔다.
- 
Metered Section#
다른 동기화 객체들 보다 100배정도 빠르고(임계구역보다는 50배) 다른 프로세스 간에도 사용 
가능
http://msdn.microsoft.com/en-us/library/ms810428.aspx
- 
참고사이트#- Thread Synchronization for Beginners
 https://secure.codeproject.com/KB/threads/Synchronization.aspx?display=Print
- Introduction to Multi-threaded Code
 http://www.codeproject.com/KB/threads/sync.aspx?display=Print
 
- Thread Synchronization for Beginners
- 
소스#
- #include<windows.h>
 #include <stdio.h>
 #include<iostream>
 #include <process.h>
 #include "MeteredSection.h"
 using namespace std;
 const int LOOP_COUNT=10000;
 //============================================================================
 /*
 Thread Synchronization for Beginners
 https://secure.codeproject.com/KB/threads/Synchronization.aspx?display=Print
 */
 //============================================================================
 // Declare the global variable
 static int g_n;
 CRITICAL_SECTION m_cs;
 ////////Thread One Function///////////////////
 UINT ThreadOne(LPVOID lParam)
 {
 
 // Lock the Critical section
 EnterCriticalSection(&m_cs);
 for(int i=0;i<10;i++)
 {
 g_n++;
 cout << "Thread 1: " << g_n << "\n";
 }
 
 //Release the Critical section
 LeaveCriticalSection(&m_cs);
 
 // return the thread
 return 0;
 }
 ////////Thread Two Function///////////////////
 UINT ThreadTwo(LPVOID lParam)
 {
 
 // Lock the Critical section
 EnterCriticalSection(&m_cs);
 
 for(int i=0;i<10;i++)
 {
 g_n++;
 cout << "Thread 2: "<< g_n << "\n";
 }
 
 //Release the Critical section
 LeaveCriticalSection(&m_cs);
 
 // return the thread
 return 0;
 }
 int main_CriticalSection0()
 {
 // Create the array of Handle
 HANDLE hThrd[2];
 
 //Thread ID's
 DWORD IDThread1, IDThread2;
 
 //Initilize the critical section
 InitializeCriticalSection(&m_cs);
 
 // Create thredas use CreateThread function with NULL Security
 hThrd[0] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) ThreadOne,(LPVOID)NULL,0,&IDThread1);
 hThrd[1] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) ThreadTwo,(LPVOID)NULL,0,&IDThread2);
 
 // Wait for the main thread
 WaitForMultipleObjects(2,hThrd,TRUE,INFINITE);
 
 // Delete critical Section
 DeleteCriticalSection(&m_cs);
 
 return 0;
 }
 //============================================================================
 //============================================================================
 /*
 Introduction to Multi-threaded Code
 http://www.codeproject.com/KB/threads/sync.aspx?display=Print
 */
 //============================================================================
 //No Synchronization
 //#include <process.h>
 //#include <stdio.h>
 int a[ 5 ];
 void Thread_NS( void* pParams )
 {
 int i, num = 0;
 int cnt=0;
 while ( 1 )
 {
 for ( i = 0; i < 5; i++ ) a[ i ] = num;
 num++;
 }
 }
 int main_NoSynchronization( void )
 {
 _beginthread( Thread_NS, 0, NULL );
 
 int cnt=0;
 while ( cnt++ <LOOP_COUNT )
 {
 printf("%d-%d %d %d %d %d\n", cnt,a[ 0 ], a[ 1 ], a[ 2 ], a[ 3 ], a[ 4 ] );
 //Sleep(500);
 }
 
 return 0;
 }
 //============================================================================
 //Critical Section Objects
 CRITICAL_SECTION cs;
 // int a[ 5 ];
 void Thread_CS( void* pParams )
 {
 int i, num = 0;
 
 int cnt=0;
 while ( 1 )
 {
 EnterCriticalSection( &cs );
 for ( i = 0; i < 5; i++ ) a[ i ] = num;
 LeaveCriticalSection( &cs );
 num++;
 }
 }
 int main_CriticalSection( void )
 {
 InitializeCriticalSection( &cs );
 _beginthread( Thread_CS, 0, NULL );
 
 int cnt=0;
 while ( cnt++ <LOOP_COUNT )
 {
 EnterCriticalSection( &cs );
 printf( "%d-%d %d %d %d %d\n", cnt,a[ 0 ], a[ 1 ], a[ 2 ], a[ 3 ], a[ 4 ] );
 
 LeaveCriticalSection( &cs );
 }
 return 0;
 }
 //============================================================================
 //Mutex
 //#include <windows.h>
 //#include <process.h>
 //#include <stdio.h>
 HANDLE hMutex;
 //int a[ 5 ];
 void Thread_Mutex( void* pParams )
 {
 int i, num = 0;
 
 while ( TRUE )
 {
 WaitForSingleObject( hMutex, INFINITE );
 for ( i = 0; i < 5; i++ ) a[ i ] = num;
 ReleaseMutex( hMutex );
 num++;
 }
 }
 int main_Mutex( void )
 {
 hMutex = CreateMutex( NULL, FALSE, NULL );
 _beginthread( Thread_Mutex, 0, NULL );
 
 int cnt=0;
 while ( cnt++ <LOOP_COUNT )
 {
 WaitForSingleObject( hMutex, INFINITE );
 printf( "%d-%d %d %d %d %d\n", cnt, a[ 0 ], a[ 1 ], a[ 2 ], a[ 3 ], a[ 4 ] );
 
 ReleaseMutex( hMutex );
 }
 return 0;
 }
 //============================================================================
 // Event
 //#include <windows.h>
 //#include <process.h>
 //#include <stdio.h>
 HANDLE hEvent1, hEvent2;
 //int a[ 5 ];
 void Thread_Event( void* pParams )
 {
 int i, num = 0;
 
 while ( TRUE )
 {
 WaitForSingleObject( hEvent2, INFINITE );
 for ( i = 0; i < 5; i++ ) a[ i ] = num;
 SetEvent( hEvent1 );
 num++;
 }
 }
 int main_Event( void )
 {
 hEvent1 = CreateEvent( NULL, FALSE, TRUE, NULL );
 hEvent2 = CreateEvent( NULL, FALSE, FALSE, NULL );
 
 _beginthread( Thread_Event, 0, NULL );
 
 int cnt=0;
 while ( cnt++ <LOOP_COUNT )
 {
 WaitForSingleObject( hEvent1, INFINITE );
 printf( "%d %d %d %d %d\n",
 a[ 0 ], a[ 1 ], a[ 2 ],
 a[ 3 ], a[ 4 ] );
 SetEvent( hEvent2 );
 }
 return 0;
 }
 //============================================================================
 //============================================================================
 //Critical Section witn Semaphore
 //Critical Section을 닫는다면 이것을 사용하는 쓰레드도 종료시켜야 한다.
 //CRITICAL_SECTION cs;
 // int a[ 5 ];
 HANDLE hSmp;
 void Thread_CS_Semaphore( void* pParams )
 {
 int i, num = 0;
 
 int cnt=0;
 while ( 1 )
 {
 EnterCriticalSection( &cs );
 
 WaitForSingleObject( hSmp, INFINITE );
 for ( i = 0; i < 5; i++ ) a[ i ] = num;
 LeaveCriticalSection( &cs );
 num++;
 }
 }
 /*
 // CRITICAL_SECTION
 typedef struct _RTL_CRITICAL_SECTION {
 PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
 LONG LockCount;
 LONG RecursionCount;
 HANDLE OwningThread; // from the thread's ClientId->UniqueThread
 HANDLE LockSemaphore;
 ULONG_PTR SpinCount; // force size on 64-bit systems when packed
 } RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
 윈도우 에서 제공하는 동기화 함수들은 내부적으로 세마포어와 스핀락 알고리즘 구현해서 사용하고 있다.
 */
 int main_CriticalSection_Semaphore( void )
 {
 /*
 //현재 문제
 몇번 루프를 돌고 더이상 실행이 되지 않는다.
 
 세마포어 카운트 최대치를 넘으면 ReleaseSemaphore()가 FLASE 리턴
 최소치와 최대치를 둘다 1000으로 맞추면 실행 10000번까지는 성공
 */
 hSmp = ::CreateSemaphore(NULL, // no security attributes
 5, // initial count
 10, // max count, 세마포어 Object(큐)의 최대치,
 NULL); // anonymous
 InitializeCriticalSection( &cs );
 //_beginthread( Thread_CS_Semaphore, 0, NULL );
 HANDLE hThrd = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) Thread_CS_Semaphore,(LPVOID)NULL,0,0);
 
 BOOL result;
 long PreCount=0;
 int cnt=0;
 while ( cnt++ <LOOP_COUNT )
 {
 EnterCriticalSection( &cs );
 
 result= ReleaseSemaphore(hSmp, 1, &PreCount );
 if(!result){
 printf( "ERROR-(%d,%d)-%d %d %d %d %d\n", cnt,PreCount,a[ 0 ], a[ 1 ], a[ 2 ], a[ 3 ], a[ 4 ] );
 //break;
 }else{
 printf( "(%d,%d)-%d %d %d %d %d\n", cnt,PreCount,a[ 0 ], a[ 1 ], a[ 2 ], a[ 3 ], a[ 4 ] );
 }
 
 LeaveCriticalSection( &cs );
 }
 //핸들 정리 전에 쓰레드를 종료 시켜야 한다.
 TerminateThread(hThrd,0);
 //핸들 정리
 ::CloseHandle(hSmp);
 ::DeleteCriticalSection(&cs);
 return 0;
 }
 //============================================================================
 //============================================================================
 //Metered Section
 //Metered Section을 닫을때(CloseMeteredSection()) 이것을 사용하는 쓰레드를 먼저 종료시켜야 한다.
 //CRITICAL_SECTION cs;
 // int a[ 5 ];
 METERED_SECTION *pms=0;
 long lMsCount=0;
 BOOL bContinue=1;
 void Thread_MeteredSection( void* pParams )
 {
 int i, num = 0;
 DWORD ret=0;
 int cnt=0;
 bContinue=TRUE;
 while ( bContinue )
 {
 EnterMeteredSection( pms,0 );
 for ( i = 0; i < 5; i++ ) a[ i ] = num;
 LeaveMeteredSection( pms, 1, &lMsCount );
 
 num++;
 }
 }
 int main_MeteredSection( void )
 {
 pms = CreateMeteredSection( 100, 100, NULL );
 
 //_beginthread( Thread_MeteredSection, 0, NULL );
 DWORD IDThread1=0;
 HANDLE hThrd = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) Thread_MeteredSection,(LPVOID)NULL,0,&IDThread1);
 // CreateThread, ExitThread, TerminateThread
 
 int cnt=0;
 while ( cnt++ <LOOP_COUNT )
 {
 EnterMeteredSection( pms,0 );//MS Count 감소
 printf( "(%d,%d) -%d %d %d %d %d\n", cnt,lMsCount,a[ 0 ], a[ 1 ], a[ 2 ], a[ 3 ], a[ 4 ] );
 
 LeaveMeteredSection( pms, 1, &lMsCount);//MS Count 증가
 }
 //TerminateThread(hThrd,0);
 bContinue=FALSE;
 CloseMeteredSection(pms);//쓰레드를 닫는 후에 호출
 return 0;
 }
 //============================================================================
 //============================================================================
 int main()
 {
 //main_CriticalSection0();
 
 //main_NoSynchronization();//51,424,706
 //main_CriticalSection(); //20000, 19947,21391
 //main_Mutex();//10000, 10050
 //main_Event();//10000
 //main_CriticalSection_Semaphore();//진행 않됨, 문제 있음
 main_MeteredSection();//4,185,518, 속도가 100배, Process간에도 가능
 
 cin.get();
 return 0;
 }
  
 Synchronization.zip
Synchronization.zip