The multithreaded classes provided with MFC fall into two categories: synchronization objects (CSyncObject, CSemaphore, CMutex, CCriticalSection, and CEvent) and synchronization access objects (CMultiLock and CSingleLock).필요한 경우, 사용자는 프로그래밍을 할 때 쓰레드를 만들게 되는데, 이 경우 자원에 대한 동기화 방식에 대해 충분한 이해를 하지 않은 상태에서 위에서 제시한 각각의 경우 중 하나를 선택하게 된다. 이것은 응용 프로그램의 성능에 충분한 영향을 미치게 된다. 하나의 응용 프로그램 내에서 여러 개의 쓰레드를 만들어 각 자원 엑세스에 대한 접근을 하기 위해 크리티컬섹션이나 뮤택스를 사용하게 되면, 운영체제를 통한 문맥교환이 이루어 지기 때문에 그만큼 쓰레드 제어함수에서 메인 프로그램으로의 전환이 느려지게 된다.
Synchronization classes are used when access to a resource must be controlled to ensure integrity of the resource. Synchronization access classes are used to gain access to these controlled resources. This topic describes when to use each class.
To determine which synchronization class you should use, ask the following series of questions:
1. Does the application have to wait for something to happen before it can access the resource (for example, data must be received from a communications port before it can be written to a file)?
If yes, use CEvent.
2. Can more than one thread within the same application access this resource at one time (for example, your application allows up to five windows with views on the same document)?
If yes, use CSemaphore.
3. Can more than one application use this resource (for example, the resource is in a DLL)?
If yes, use CMutex.
If no, use CCriticalSection.
CSyncObject is never used directly. It is the base class for the other four synchronization classes.
CWinThread *th; // TODO: Add your control notification handler code here th = AfxBeginThread(ThreadProc,this,0, 0, CREATE_SUSPENDED,0);쓰레드를 생성하는 방법을 보면, 먼저 쓰레드 개체의 인스턴스를 정의하고, 쓰레드 생성 시 대기 상태로 쓰레드를 생성해야 한다. 생성과 동시에 바로 쓰레드 제어함수로 제어권을 보내게 되면 정상적인 쓰레드 처리가 불가능한 에러가 발생할 수 있다. 그리고 쓰레드를 종료하기 위해서는 대기 상태로 보내는 것이 아니라 완전히 메모리에서 제거해 주어야 한다. 일반적으로 쓰레드를 사용하는 경우 대기 상태로 변경하는 실수를 흔히 많이 사용하는 것을 볼 수 있다. 그리고 쓰레드를 사용하게 되는 시점에서 해당 쓰레드를 재시작시키는 방법을 사용하여야 한다.
// TODO: Add your control notification handler code here th->ResumeThread();쓰레드 제어 코드를 다음 예시와 같이 제시한다. 이 예제에서는 뮤텍스를 이용한 쓰레드 공유방법을 제시하고 있다.
CMutex m_ThreadMutex; UINT __cdecl ThreadProc( LPVOID pParam ) { CSingleLock singleLock(&m_ThreadMutex); CTestMFCDlg* dlg = (CTestMFCDlg *)pParam; static int i=1000; do { // 쓰레드는 메인 프로그램과 별개의 프로세스 ID를 가지고 실행됨으로 // SetDlgItemText 함수를 사용함, UpdateData()함수를 사용하려면 사용자 메시지를 이용해야 함 SetDlgItemText(dlg->m_hWnd, IDC_STATIC, L"Lock, m_iValue & TextEdit"); Sleep(1000); WaitForSingleObject(th, INFINITE); singleLock.Lock(); // 공유자원을 사용함 dlg->m_iValue = 100; if (endThread == TRUE) { SetDlgItemInt(dlg->m_hWnd, IDC_EDIT1, 0, 0); AfxEndThread(0, TRUE); // 쓰레드 종료 break; } else SetDlgItemInt(dlg->m_hWnd, IDC_EDIT1, i++, 0); Sleep(2000); SetDlgItemText(dlg->m_hWnd, IDC_STATIC, L"UnLock, m_iValue & TextEdit "); singleLock.Unlock(); // 공유자원 반납 Sleep(1000); } while(TRUE) return 0; }그림과 같이 쓰레드를 실행하게 되면 m_ivalue 값을 증가시키는 자원(전역변수, 에디트 박스)을 해당 쓰레드가 락을 건 후 다른 쓰레드로 하여금 접근하지 못하게 하고, m_ivalue 값을 증가시킨 후 에디트 박스에 표시한다.
HINSTANCE hDll; CMutex m_ThreadMutex; Thread_Porc() { CSingleLock singleLock(&m_ThreadMutex); // 뮤텍스 생성 WaitForSingleObject(th, INFINITE); // 먼저 실행된 쓰레드의 종료를 기다림 singleLock.Lock(); // 공유자원을 사용함 typedef int (*FuncMySum) (int varx, int var y); // Dll 내의 함수원형 FuncMySum lpCalc; Int SumOfAdd; hDll = LoadLibrary(Calc.dll"); // Dll 로딩 lpCalc = (FuncMySum) GetProcAddress(hDll, "sum"); // sum 함수의 포인터를 지정함 SumOfAdd =lpCalc(5,3); // Dll 내의 sum 함수 호출 TRACE("%d + %d = %d ", 5, 3, SumOfAdd); FreeLibrary(hDll); // Dll 언로딩 singleLock.Unlock(); // 공유자원 반납 return 0; }쓰레드에서 Dll을 사용하는 경우, 가급적 간접 로딩(Explicit) 방식으로 필요한 Dll만 메모리에 로딩을 하고, 다 사용한 다음에서 이 Dll을 언로딩하는 방법을 사용하는 것이, 다수의 응용 프로그램 내에서 각각의 쓰레드 경쟁을 피할 수 있으며, 예기치 못한 에러로부터 정상적인 프로그램의 실행을 보장 받을 수 있다. 그리고 필요하다면, 각 쓰레드의 실행 시간을 검사해 봄으로써 실제 쓰레드 동기화에 얼마나 많은 시스템 클럭이 필요한지를 확인 해 볼 수 있다.
이전 글 : 빅 데이터와 시민권에 대하여
다음 글 : 새로운 세계에 대한 새로운 윤리
최신 콘텐츠