반응형
/* 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); }
반응형
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."