본문 바로가기
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);
    }
    반응형

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