본문 바로가기
IT창고/System

스레드/동기화/비동기/크리티컬섹션/뮤텍스

by 창구창고 2007. 1. 22.
반응형
/*
1. 스레드는 각자의 스택을 가진다.
2. 멀티스레드 환경에서 지역변수는 안전하다.	-어떤것을 얼마나 사용하던 상관이 없다.
3. 멀티 스레드 환경에서 전역(static 지역) 변수는 불안하다. 
	반드시 동기화 해야한다.
	CriticalSection, Mutex, Semaphore, Event 등의 기범을 사용해야한다.

  - CriticalSection 구역에는 반드시 하나의 스레드만 존재한다. -  상호 배제
    구역을 들어가기 전에 Enter() 나가면 Leave()먼저 온것이 들어가면 나중에 온것은 먼저 온것이 나갈때까지 기다려야한다.- 독점
	하지만 먼조 온 스레드가 나가더라도 다시 실행하려고 하면 두 스레드는 다시 경쟁상태에 놓이게 된다.
*/
/*
#include<windows.h>
#include<stdio.h>

void Delay(){	for(int i = 0 ; i < 20000000 ; i++);	}//시간지연

//BOOL bWait = TRUE;
CRITICAL_SECTION cs;

DWORD WINAPI foo(void *p)
{
	char * name	=	(char *)p;
	static int x = 0;
	for (int i = 0 ; i < 20 ; i++)
	{
		EnterCriticalSection(&cs);	//	CriticalSection에 들어간다.
		//========================================================
		x = 100; Delay();
		x =x + 1; Delay();
		printf("%s : %d\n",name,x);	Delay();
		//========================================================
		LeaveCriticalSection(&cs);	// CriticalSection에서 나온다.
	}

	printf("Finish...%s\n",name);
//	bWait = FALSE;
	return 0;
}
//메인은 스레드 하나를 만들어 놓고 죽는다. 즉 주 스레드가 죽는것이다.
//이 경우 생성된 스레드도 같이 죽는다. 이유는 프로세스가 죽기 때문.
void main()
{
	InitializeCriticalSection(&cs);	// 아래에 반드시 DeleteCriticalSection()이 존재해야 한다.

	HANDLE h1 = CreateThread(0,0,foo,"A",0,0);
	HANDLE h2 = CreateThread(0,0,foo,"\tB",0,0);

	//스레드는 죽을때 시그널 된다.
	//WaitForSingleObject(h1,INFINITE); //하나만 대기한다.
	HANDLE h[2]	=	{h1,h2};
	//64개까지 가능하다.
	WaitForMultipleObjects(2,h,TRUE,INFINITE);	//여러개를 대기한다. 여기서는 2개가 모두 시그널 될때까지 대기한다.
	//while(bWait);//절대 사용하면 안되는 최악의 방법 하는일 없이 CPU를 사용하게 된다.
	CloseHandle(h1);//사실상 여기서 종료를 안해도 프로그램이 종료한다.
	CloseHandle(h2);

//	ExitThread(0);	// 현재 프로세스만 종료	-> 자신만 종료 즉 주 스레드만 종료 
	//return ;		// 프로세스의 종료
	
	DeleteCriticalSection(&cs);
}
*/
/*
CriticalSection관련함수 4개
CRITICAL_SECTION 변수명; <~ 변수 설정
EnterCriticalSection();
LeaveCriticalSection();
InitializeEnterCriticalSection();
DeleteCriticalSection();
*/
/*#include<windows.h>
#include<iostream>
#include<list>
using namespace std;

list<int> st;	//전역 객체(모든 멤버가 static에 있으므로 모든 스레드의 의해 공유된다 접근시 동기화가 필요하다.
#define COUNT 10
DWORD WINAPI foo(void *p)
{
	for(int i = 1 ; i < 10 ; i++)
	{
		for(int j = 1 ; j < COUNT; j++)
		{
			st.push_back(10);			//링크드 리스트 접근
		}
		printf("foo : %d\n",i);
	}
	return 0;
}
DWORD WINAPI goo(void *p)
{
	for(int i = 1 ; i < 10 ; i++)
	{
		for(int j = 1 ; j < COUNT; j++)
		{
			st.push_back(10);			//링크드 리스트 접근
		}
		printf("goo : %d\n",i);
	}
	return 0;
}
void main()
{
	HANDLE h[2];
	h[0]	=	CreateThread(0,0,foo,0,0,0);
	h[1]	=	CreateThread(0,0,goo,0,0,0);

	WaitForMultipleObjects(2,h,TRUE,INFINITE);

	CloseHandle(h[0]);
	CloseHandle(h[1]);
}*/
/*
#include<windows.h>
#include<iostream>
#include<list>
using namespace std;

list<int> st;	//전역 객체(모든 멤버가 static에 있으므로 모든 스레드의 의해 공유된다 접근시 동기화가 필요하다.
#define COUNT 50000
//리스트를 통기화 하기 위한 크리티걸 섹션
CRITICAL_SECTION cs;
CRITICAL_SECTION cs2; //printf()를 위한 동기화

DWORD WINAPI foo(void *p)
{
	for(int i = 1 ; i < 10 ; i++)
	{
		for(int j = 1 ; j < COUNT; j++)
		{
			EnterCriticalSection(&cs);
			st.push_back(10);			//링크드 리스트 접근
			LeaveCriticalSection(&cs);
		}
		EnterCriticalSection(&cs2);
		printf("\tfoo : %d\n",i);
		LeaveCriticalSection(&cs2);
	}
	return 0;
}
DWORD WINAPI goo(void *p)
{
	for(int i = 1 ; i < 10 ; i++)
	{
		for(int j = 1 ; j < COUNT; j++)
		{
			EnterCriticalSection(&cs);
			st.push_back(10);			//링크드 리스트 접근
			LeaveCriticalSection(&cs);
		}
		EnterCriticalSection(&cs2);
		printf("goo : %d\n",i);
		LeaveCriticalSection(&cs2);
	}
	return 0;
}
void main()
{
	InitializeCriticalSection(&cs);	
	InitializeCriticalSection(&cs2);	
	HANDLE h[2];
	h[0]	=	CreateThread(0,0,foo,0,0,0);
	h[1]	=	CreateThread(0,0,goo,0,0,0);

	WaitForMultipleObjects(2,h,TRUE,INFINITE);

	CloseHandle(h[0]);
	CloseHandle(h[1]);
	DeleteCriticalSection(&cs);
	DeleteCriticalSection(&cs2);
}*/
// Thread - Safe 클래스 : 싱글 스래드나 멀티 스레드 환경에서 아무 문제 없이 
						//사용 할 수 있다.(즉 자신이 스스로를 동기화 하고 있다.)
//stl의 list에서 파생된 클래스를 만든다.

/*
Serialization : 동시에 수행중이던 스레드가 어떤 지점을 직렬로 차례로 통과 하게 되는 것을 일컫는 용어
				주의 : MFC에서는 다른 용도로 이 용어를 사용하기도 한다.
*/
/*
#include<windows.h>
#include<iostream>
#include<list>
using namespace std;

CRITICAL_SECTION cs;
template<typename T>class Safe_List : public list<T>
{
	CRITICAL_SECTION m_cs;
public:
	Safe_List()
	{
		InitializeCriticalSection(&m_cs);
	}
	~Safe_List()
	{
		DeleteCriticalSection(&m_cs);
	}

	//부모함수 오버라이드
	void push_back(const T& x)
	{
		EnterCriticalSection(&m_cs);
		list<T>::push_back(x);	//	부모의 원래 기능 사용
		LeaveCriticalSection(&m_cs);
	}
};

Safe_List<int> st;	//전역 객체(모든 멤버가 static에 있으므로 모든 스레드의 의해 공유된다 접근시 동기화가 필요하다.
#define COUNT 10
DWORD WINAPI foo(void *p)
{
	for(int i = 1 ; i < 100000 ; i++)
	{
		for(int j = 1 ; j < COUNT; j++)
		{
			st.push_back(10);			//링크드 리스트 접근
		}
		EnterCriticalSection(&cs);
		printf("foo : %d\n",i);
		LeaveCriticalSection(&cs);
	}
	return 0;
}
DWORD WINAPI goo(void *p)
{
	for(int i = 1 ; i < 100000 ; i++)
	{
		for(int j = 1 ; j < COUNT; j++)
		{
			st.push_back(10);			//링크드 리스트 접근
		}
		EnterCriticalSection(&cs);
		printf("\tgoo : %d\n",i);
		LeaveCriticalSection(&cs);
	}
	return 0;
}
void main()
{
	InitializeCriticalSection(&cs);
	HANDLE h[2];
	h[0]	=	CreateThread(0,0,foo,0,0,0);
	h[1]	=	CreateThread(0,0,goo,0,0,0);

	WaitForMultipleObjects(2,h,TRUE,INFINITE);

	CloseHandle(h[0]);
	CloseHandle(h[1]);
	DeleteCriticalSection(&cs);
}*/

/*
1. 스택은 스레드별로 하나씩 갖는다.
2. 스태틱은 프로세스가 1개 갖는다.
3. 쓰래드별로 하나의 스태틱을 갖고 싶다 - 생긴게 -> ThreadLocalStrorage 
*//*
#include<windows.h>
#include<iostream>
#include<list>
using namespace std;

void goo(char  * name)
{
	//TLS 공가넹 변수를 생성한다.
	__declspec(thread) static int c = 0;
	++c;
	printf("%s : %d\n",name,c );	// 함수가 몇번 호출되었는지 알고 싶다.
}
DWORD WINAPI foo(void *p)
{
	char * name = (char *)p;
	goo(name);
	goo(name);
	goo(name);
	return 0;
}
void main()
{
	//InitializeCriticalSection(&cs);
	HANDLE h[2];
	h[0]	=	CreateThread(0,0,foo,"A",0,0);
	h[1]	=	CreateThread(0,0,foo,"\tB",0,0);

	WaitForMultipleObjects(2,h,TRUE,INFINITE);

	CloseHandle(h[0]);
	CloseHandle(h[1]);
	//DeleteCriticalSection(&cs);
}*/
/*
정리 :
어떤 함수가 내부적으로 지역변수만 사용한다. -> 멀티 스레드에 안전한가?(안전)
어떤 함수가 내부적으로 static 변수를 사용한다.	-> 싱글스레드는 문제 없다.
												-> 멀티 스레드는 안전한가? (불안전)

1.VC++의경우 LIBC.lib에 C표준 함수가 들어있다. - 싱글 스레드용
2.LIBCMT.lib  - 멀티스레드용 - 스레드를 사용하기 위해서는 초기화가 필요하다 
							- 대신해주는것 -> _beginthreadex()
*/
/*
#include<stdio.h>
#include<process.h>		//	_beginthreadex()를 사용하기 위해
#include<windows.h>

unsigned long __stdcall foo(void *p)	//	결국 DWORD WINAPI foo(void *p)
{
	printf("foo\n");
	return 0;
}

void main()
{
	unsigned long h=_beginthreadex(0,0,foo,0,0,0);

	WaitForSingleObject((HANDLE)h,INFINITE);
	CloseHandle((HANDLE)h);
}
*/
/*
프로그램을 만들때 
C의 많은 함수를 사용한다.(strtok()같은 함수 ) _beginthreadex()를 사용해야 한다.

순수 Win32API를 만을 사용한다 -> CreateThread() 사용
순수 Win32API와 C의 일부 함수들 (스레드에 안전한) - > CreateThread()를 사용해도 되자만
													확신이 없다면 _beginthreadex() 사용
MFC 사용 : AfxBegineThread() 라는 MFC전용 함수를 사용한다.
*/
#include<windows.h>
#include<stdio.h>
#include<conio.h>

void main()
{
	HANDLE hMutex	=	CreateMutex(0,			//보안속성
									FALSE,		//소유권여부
									"m");		//뮤텍스 KO이름
	printf("뮤텍스를 대기 합니다.\n");

	WaitForSingleObject(hMutex,INFINITE);

	printf("뮤텍스를 획득했습니다.\n");

	getch();

	ReleaseMutex(hMutex);
	CloseHandle(hMutex);
}
반응형

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."