멀티 쓰레드 동기화(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

 

 

 

  • 소스#


 

  1. #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;
    }

 

반응형

'Code' 카테고리의 다른 글

APM 설치  (0) 2012.08.11
Memory Mapped File  (0) 2012.08.01
Quake 3 source build  (0) 2008.11.18
filemon , regmon source  (0) 2008.11.08
[vb6] Visual Basic 6에서 마우스 휠 사용하기  (0) 2008.11.05
Posted by codens