728x90

임계 영역 접근 동기화

- 메모리 접근의 동기화

- 임계 영역 : 한 순간에 하나의 쓰레드만 접근이 요구되는 공유 리소스에 접근하는 코드 블록

 

유저 모드 동기화

- 크리티컬 섹션 기반의 동기화

    -> key : 둘 이상의 쓰레드 접근을 막기 위해 열쇠를 이용한다고 생각하면 됨

    -> CRITICAL_SECTION : 크리티컬 섹션 기반의 동기화에서의 키

void InitializeCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection
);

    -> InitializeCriticalSection()

        * 열쇠 생성 후 초기화. 임계 영역 접근에 관련된 것을 초기화

        * 동기화 기법을 적용하기 위한 최소한의 기본 작업을 내부적으로 처리하기 위해 요청

void EnterCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection
);

    -> EnterCriticalSection()

        * 임계 영역의 시작

        * 열쇠를 획득하고 임계 영역에 접근

void LeaveCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection
);

    -> LeavCriticalSection()

        * 임계 영역의 끝

        * 열쇠를 반환하고 임계 영역을 빠져나옴

void DeleteCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection
);

    -> DeleteCriticalSection()

        * 열쇠 소멸

    -> EnterCriticalSection ~ LeaveCriticalSection을 임계영역으로 결정

    -> 둘 이상의 쓰레드가 함수에 접근할 때 하나의 쓰레드가 먼저 EnterCriticalSection 함수에 진입했다면 LeaveCriticalSection에 도달할 때 까지 다른 쓰레드는 blocked 상태가 됨

    -> 그렇기 때문에 임계 영역의 범위는 최소한으로 해야 효율적

#include <stdio.h>
#include <Windows.h>
#include <tchar.h>
#include <process.h>

#define NUM_OF_GATE	6

LONG gTotalCount = 0;		// 둘 이상의 쓰레드가 접근하는 변수

CRITICAL_SECTION cSection;

void IncreaseCount()
{
	EnterCriticalSection(&cSection);		// 임계 영역 시작
	gTotalCount++;
	LeaveCriticalSection(&cSection);		// 임계 영역 끝
}

unsigned int WINAPI ThreadProc(LPVOID lpParam)
{
	for (DWORD i = 0; i < 1000; i++)
	{
		IncreaseCount();
	}
	return 0;
}

int _tmain(int argc, TCHAR* argv[])
{
	DWORD	dwThreadId[NUM_OF_GATE];
	HANDLE	hThread[NUM_OF_GATE];

	InitializeCriticalSection(&cSection);

	for (DWORD i = 0; i < NUM_OF_GATE; i++)
	{
		hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, NULL, CREATE_SUSPENDED, (unsigned*)& dwThreadId[i]);
		if (hThread[i] == NULL)
		{
			_tprintf(_T("Thread create error\n"));
			return -1;
		} // 쓰레드를 생성하지 못하면 NULL이 반환
	}
	
	for (DWORD i = 0; i < NUM_OF_GATE; i++)
	{
		ResumeThread(hThread[i]);
	}

	WaitForMultipleObjects(NUM_OF_GATE, hThread, TRUE, INFINITE);	// 쓰레드가 종료될 때까지 대기

	_tprintf(_T("total count : %d \n"), gTotalCount);

	for (DWORD i = 0; i < NUM_OF_GATE; i++)
	{
		CloseHandle(hThread[i]);
	}

	DeleteCriticalSection(&cSection);

	return 0;
}

- 인터락 함수 기반의 동기화

    -> 간편하게 임계 영역을 설정하기 위한 동기화 기법

    -> 원자적 접근 보장 : 한 순간에 하나의 쓰레드에 의해서만 호출이 완료되도록 허용

LONG InterlockedIncrement(
  LONG volatile *Addend
);

LONG InterlockedDecrement(
  LONG volatile *Addend
);

    -> InterlockedIncrement() / InterlockedDecrement()

        * 전달된 변수의 값을 하나 증가 / 감소 시킴

#include <stdio.h>
#include <Windows.h>
#include <tchar.h>
#include <process.h>

#define NUM_OF_GATE	6

LONG gTotalCount = 0;		// 둘 이상의 쓰레드가 접근하는 변수

void IncreaseCount()
{
	// gTotalCount++;
	InterlockedIncrement(&gTotalCount);
}

unsigned int WINAPI ThreadProc(LPVOID lpParam)
{
	for (DWORD i = 0; i < 1000; i++)
	{
		IncreaseCount();
	}
	return 0;
}

int _tmain(int argc, TCHAR* argv[])
{
	DWORD	dwThreadId[NUM_OF_GATE];
	HANDLE	hThread[NUM_OF_GATE];

	for (DWORD i = 0; i < NUM_OF_GATE; i++)
	{
		hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, NULL, CREATE_SUSPENDED, (unsigned*)& dwThreadId[i]);
		if (hThread[i] == NULL)
		{
			_tprintf(_T("Thread create error\n"));
			return -1;
		} // 쓰레드를 생성하지 못하면 NULL이 반환
	}
	
	for (DWORD i = 0; i < NUM_OF_GATE; i++)
	{
		ResumeThread(hThread[i]);
	}

	WaitForMultipleObjects(NUM_OF_GATE, hThread, TRUE, INFINITE);	// 쓰레드가 종료될 때까지 대기

	_tprintf(_T("total count : %d \n"), gTotalCount);

	for (DWORD i = 0; i < NUM_OF_GATE; i++)
	{
		CloseHandle(hThread[i]);
	}

	return 0;
}

 

 

728x90

+ Recent posts