예를 들어 8개의 스레드가 돌고 있는데 모두 같은 리소스를 사용한다고 가정 하면 이 스레드들은 레이싱 컨디션에 들어간다.

 

이 때, 크리티컬 섹션/뮤텍스를 사용하면 7개를 스탑시키고 한개를 리소스에 접근시켜야 함

그러나 세마포어는 2개이상의 스레드를 접근시키고 나머지는 대기할 수 있도록 하는 것이 가능하다.

 

따라서 크리티컬 섹션/뮤텍스는 두 개의 스레드를 교차 실행 시켜야 할 때.

 

1. 프로젝트 생성, 단일문서기반,  (서비스팩이 설치되어 있다면 오피스 2003)

 

2. stdafx.cpp

CString g_arString[10];
CSemaphore g_SP(3,3);

 

stdafx.h에 <afxmt.h>인클루드

 

extern CString g_arString[10];
extern CSemaphore g_SP;

 

3. Semaphore.h파일의 CwinApp클래스에 CEvent 객체 추가

 

class CSemaphoreApp : public CWinApp
{
 public:
     CSemaphoreApp();
     CEvent m_ExitEvent;    // 종료이벤트

 

 

객체 초기화-> 생성자를 부른다.어플리케이션 클래스의 생성자 함수 안에서 초기화

CSemaphoreApp::CSemaphoreApp()
:m_ExitEvent(FALSE, TRUE)
{
     // TODO: 여기에 생성 코드를 추가합니다.
     // InitInstance에 모든 중요한 초기화 작업을 배치합니다.
}

 

4. SemaphoreApp에 ExitInstance() 함수 재정의

int CSemaphoreApp::ExitInstance()
{
     m_ExitEvent.SetEvent();

     ::Sleep(1000);

 

     return CWinApp::ExitInstance();
}

5. 특정 클래스 안에 멤버함수로 스레드 만들기(지난번에 한것은 전역함수로 스레드를 만듬)

SemaphoreApp클래스 속성에서 함수 추가

반환 형식: UINT

매개 변수 형식: LPVOID

함수 이름: threadSemaphore

액세스: public

매개 변수 이름: pParam 추가

static(정적함수) 생성

주석: App 클래스에 멤버로서 포함되어진 스레드

 

-> 실제 함수 추가시에 직접 코드를 작성하는 것이 더 편할 수 있다.

하지만 마법사를 이용할경우 헤더파일에 선언부를 자동으로 함께 만들어준다는 장점이 있다.

 

UINT CSemaphoreApp::ThreadSemaphore(LPVOID pParam)
{
     CString strTmp = _T("");
     int nIndex = (int)(pParam);

     

     g_arString[nIndex] = _T("");
     while(::WaitForSingleObject(theApp.m_ExitEvent, 10) == WAIT_TIMEOUT)
     {
         g_arString[nIndex].Format(TEXT("%d Thread is waiting!!"), nIndex);

  

         g_SP.Lock();
         g_arString[nIndex].Format(TEXT("##%d Thread is running!!"), nIndex);
         ::Sleep(100);
         g_SP.Unlock();
     }
     return 0;
}

 

6. Semaphore.cpp에

 for(int i=0; i<10; ++i)
 {
      AfxBeginThread(CSemaphoreApp::ThreadSemaphore, (LPVOID)i);
 }

 

7. 화면에 뭔가 보여주기 위한 작업

뷰클래스에 WM_Create메시지 추가, 여기에 타이머 설정

int CSemaphoreView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
     if (CView::OnCreate(lpCreateStruct) == -1)
          return -1;

     

     SetTimer(100, 1000, NULL);
     // TODO:  여기에 특수화된 작성 코드를 추가합니다.

     

     return 0;
}

 


뷰클래스에 WM_Timer메시지 추가

void CSemaphoreView::OnTimer(UINT_PTR nIDEvent)
{
     CClientDC dc(this);
     dc.FillSolidRect(0, 0, 300, 300, RGB(255, 255, 255));
     for (int i=0;i<10;i++)
     {
          if(g_arString[i].GetAt(0) == '#')
               dc.SetTextColor(RGB(192, 0, 0));
          else
               dc.SetTextColor(RGB(192, 192, 192));

  

         dc.TextOut(30, 20 * i + 10, g_arString[i]);
 }

 

 CView::OnTimer(nIDEvent);
}

 

 

OS가(커널) 스레드를 대기시키고 다른 스레드를 실행하는 기준?

UINT CSemaphoreApp::ThreadSemaphore(LPVOID pParam)
{
     CString strTmp = _T("");
     int nIndex = (int)(pParam);

     g_arString[nIndex] = _T("");
 

     while(::WaitForSingleObject(theApp.m_ExitEvent, 10) == WAIT_TIMEOUT)
     {
          g_arString[nIndex].Format(TEXT("%d Thread is waiting!!"), nIndex);

          g_SP.Lock();
          g_arString[nIndex].Format(TEXT("##%d Thread is running!!"), nIndex);
          ::Sleep(100);
          g_SP.Unlock();
     }
     return 0;

}

 

--> 여기서 while문의 이해가 중요

 

/*다음의 의미를 구별*/

이벤트: 키보드/마우스의 움직임과 같은 행위 그 자체. 행위를 나타내는 일종의 신호(데이터)

메시지:

이벤트 처리기:

메시지 처리기(메시지 처리 함수): 이벤트의 신호에 대응해서 큐에 들어온 메시지를 처리하는 함수

<크리티컬섹션/뮤텍스/세마포어>

스레드를 멈추는것이 목적이 아님.

실행되고 있는 스레드끼리 부딪히는것을 막음.


Posted by 마마필로 :