공부

쓰레드 동기화, 임계영역 접근 동기화

글로벌디노 2020. 8. 6. 21:28

쓰레드 동기화

 

유저모드 동기화

커널 모드로의 전환이 불필요하기 때문에 성능상의 이점이 있다. 다만 그만큼 기능상의 제한도 있다.

 

커널모드 동기화

커널에서 제공하는 동기화 기능을 활용하는 방법. 커널 모드로의 변경이 필요하고 이는 성능의 저하로 이어진다. 하지만 유저모드 동기화에서 제공하지 못하는 기능을 제공받을 수 있다.

 

 

동기화가 필요한 프로그램

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

#define NUM_OF_GATE 6

LONG gTotalCount = 0;

void IncreaseCount()
{
	++gTotalCount;	// 임계영역
}

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

	return 0;
}

int _tmain()
{
	HANDLE hThread[NUM_OF_GATE];

	for (DWORD i = 0; i < NUM_OF_GATE; i++)
	{
		hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, NULL, CREATE_SUSPENDED, NULL);

		if (hThread[i] == NULL)
		{
			_tprintf(_T("Thread Creation Fail <%d> \n"), i);
				return -1;
		}
	}

	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;
}

 

6개의 쓰레드가 실행된다

각각의 쓰레드에서는 전역변수 gTotalCount 를 1000번씩 증가시킨다

출력될 gTotalCount의 예상 값은 6000 이다

 

 

출력결과

나중에 이런 코드가 있다면 어떻게 디버깅을 해야할까 .. ㅎㅎ

 

 

유저 모드의 동기화

크리티컬 섹션(Critical Section) 기반의 동기화

크리티컬 섹션 = 임계영역

운영체제 교과서에서는 "상호 배제 동기화(Mutual-Exclution Synchronization)" 라고 한다

 

크리티컬 섹션 오브젝트

CRITICAL_SECTION gCriticalSection;

 

초기화

void InitializeCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection
);

 

사용

void EnterCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection
);

 

반환

void LeaveCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection
);

 

리소스 해제

void DeleteCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection
);

 

 

임계영역 접근 동기화 기법 적용

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

#define NUM_OF_GATE 6

LONG gTotalCount = 0;

CRITICAL_SECTION gCriticalSection;

void IncreaseCount()
{
	EnterCriticalSection(&gCriticalSection);
	++gTotalCount;	// 임계영역
	LeaveCriticalSection(&gCriticalSection);
}

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

	return 0;
}

int _tmain()
{
	HANDLE hThread[NUM_OF_GATE];

	InitializeCriticalSection(&gCriticalSection);

	for (DWORD i = 0; i < NUM_OF_GATE; i++)
	{
		hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, NULL, CREATE_SUSPENDED, NULL);

		if (hThread[i] == NULL)
		{
			_tprintf(_T("Thread Creation Fail <%d> \n"), i);
				return -1;
		}
	}

	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(&gCriticalSection);

	return 0;
}

출력결과

여러번 다시 실행해도 6000이 출력된다

반응형