이벤트 PULS 뮤텍스? -----------------------------------------------------------------------------------------

동기화 방법이 여러가지 있는 관계로 당연히 혼용하여 쓸수 있게 된다.

이벤트 오브젝트를 통하면 작업과정은 동일하게 할수 있어도 소비자가 2명이라면 그 2명의 소비자가 동시에 가게에 들어오는 경우가 생길 수가 있다. 그런 과정 자체가 혹은 소비자가 3명일 수도 혹은 4명일수도 있는 것이다.

즉 그 2명의 소비자의 동기화를 위해서 뮤텍스를 사용하는 방식을 보여준다.


unsingned int WINAPI OutPutTAhreadFunction1(LPVOID lpParam) -> 첫번째 쓰레드 함수

unsingned int WINAPI OutPutTAhreadFunction2(LPVOID lpParam) -> 두번째 쓰레드 함수


unsingned int WINAPI OutPutTAhreadFunction1(LPVOID lpParam)

{

WaitForSingleObject(hEvent, INFINITE); -> 메인쓰레드에서 작업하는 내용을 작업해주고 이벤트 동기화를 먼저 해준다음

WaitForSingleObject(hMutex, INFINITE); -> 뮤텍스를 통해서 작업결과물에 2개의 쓰레드가 동시에 접근하는 것을 동기화 시킨다.

코드 내용 전역변수 사용

ReleaseMutex(hMutex)

}

unsingned int WINAPI OutPutTAhreadFunction2(LPVOID lpParam)

{

WaitForSingleObject(hEvent, INFINITE); -> 메인쓰레드에서 작업하는 내용을 작업해주고 이벤트 동기화를 먼저 해준다음

WaitForSingleObject(hMutex, INFINITE); -> 뮤텍스를 통해서 작업결과물에 2개의 쓰레드가 동시에 접근하는 것을 동기화 시킨다.

코드 내용 

ReleaseMutex(hMutex)

}

Posted by JJOREG

실행 순서의 동기화 -----------------------------------------------------------------------------------------


이전까지 하나의 공유객체에 대해서 접근하는 방법에 대해서 알아보았다.
다음은 쓰레드의 실행순서를 동기화하는 차례이다.
쓰레드의 연산이나 메모리에 접근하는 실행순서를 동기화 한다.

A, B, C쓰레드가 있다고 할때 A의 연산결과를 B가 받아서 연산하고 B의 연산결과를 C가 받아서 연산해야 한다면 A B C는 순차적으로 실행되어야 한다. 이러한 상황을 위해서 실행 순서의 동기화가 필요하다. 순차적으로 실행되지 않는다면 분명 원하지 않는 값이 나오거나 이상한 값이 나올것이 뻔하다.


이벤트 기반의 동기화 -----------------------------------------------------------------------------------------

이벤트 기반의 동기화 모델에 있어서 프로그램의 추상화 개념과 비슷하게 비교해 본다면. A와 B쓰레드가 존재하고 A 쓰레드는 생산자, B 쓰레드는 소비자라는 개념을 든다.

"A생산자가 특정 물건을 만들기 전까지는 B소비자는 물건을 소비할 수 없다."

다른 비유를 들어보다면 이런 느낌을 가질 수 있습니다.

"A생산자가 가게문을 열기전까지 B소비자는 가게안에 들어와 물건을 구매할 수 없다."

커널기반이므로 당연히 윈도우에서 이에대한 지원 함수가 존재합니다.

-> 사용 방식

HANDLE CreateEvent(

  LPSECURITY_ATTRIVUTES lpEventAttributes, 

  BOOL bManualReset,

  BOOL bInitialState,

  LPCTSTR lpName

);

  LPSECURITY_ATTRIVUTES lpEventAttributes, -> 보안속성 지정

  BOOL bManualReset,-> 가장 중요한 전달인자 수동리셋모드로 이벤트 오브젝트를 생성하느냐, 자동 리셋 모드로 이벤트 오브젝트를 생성하느냐를 결정짓는다. TRUE로하면 수동리셋모드 FALSE가 전달될 경우 자동리셋 모드로 이벤트의 커널 오브젝트가 생성된다.

  BOOL bInitialState -> 이벤트 오브젝트의 초기상태를 설정한다. TRUE가 전달될 경우 Signaled 상태의 이벤트 오브젝트가 생성되고, FALSE가 전달될 경우 Non-Signaled 상태의 이벤트가 생성된다.

  lpName 이벤트 오브젝트에 이름을 줄 경우에 사용하는 전달인자이다. NULL을 전달하면 이름 없는 이벤트 오브젝트가 생성된다.


-> 종료 방식

  이벤트 오브젝트를 소멸시킬 때에는 다른 커널 오브젝트와 마찬가지로 CloseHandle 함수를 사용하면 된다.


 여기서 잠깐! WaitForSingleObject -----------------------------------------------------------------------------

 커널 오브젝트를 읽을때 그냥 넘어갔던 함수가 있었는데 여기서 다시 설명해야할 듯 하다. WaitForSingleObject함수가 존재하는데 이 함수는 핸들을 인자로 적용해서 커널 오브젝트의 상태를 확인하는데 사용되는 함수이다. 

 DWORD WaitForSingleObject {

HANDLE hHandle,         -> 커널 오브젝트의 핸들

DWORD dwMilliseconds -> 커널오브젝트가 종료될때까지 기다려주는 값 밀리세컨트단위를 사용한다.

}

이 함수가 반환하는 값은 다음과 같다.

 Priority 

 meaning 

 WAIT_OBJECT_0

 커널 오브젝트가 Signaled 상태가 되면 반환하는 값

 WAIT_TIMEOUT

 커널 오브젝트가 Signaled 상태가 되지 않고, dwMilliseconds 인자를 통해서 설정된 시간이 다 된 경우에 반환하는 값

 WAIT_ABANDONED

 소유 관계와 관련하여 함수가 정상적이지 못한 오류 발생에 의해서 반환되는 값


이벤트 기반의 동기화의 개념 -----------------------------------------------------------------------------------

  앞선 설명으로 커널 오브젝트는 이벤트 커널 오브젝트는 다른 쓰레드나 프로세스의 커널 오브젝트와 달리 자동으로 Signaled상태가 되지 않는다. 순서로 설명하자면.

 1. 이벤트 오브젝트 핸들을 전역으로 선언

 2. 메인 쓰레드가 이벤트 오브젝트를 생성한다.

 3. 쓰레드 A를 생성한다.

 4. 쓰레드 A에서 hEvent WaitForSingleObject를 호출한다. 이 의미는 이벤트가 signaled가 되기를 기다리는 것을 의미한다.

 5. 메인쓰레드에서는 쓰레드A의 핸들로 WaitForSingleObject를 호출한다.

 이 경우 4번의 과정에서 WaitForSingleObject의 호출로 signaled상태가 된 이벤트 오브젝트는 어떠한 상태가 될 것인가?

 signaled인가? Non-signaled인가?  

 정답은 BOOL bManualReset인자가 TRUE(수동 리셋 모드)라면  signaled.

 bManualReset인자가 FALSE(자동 리셋 모드)라면  Non-signaled이다.


정리하자면.

1. 이벤트 커널 오브젝트는 프로그래머의 요청에 의해서 Signaled 상태가 된다.

2. Non-Signaled 상태의 이벤트 오브젝트 때문에 WaitForSingleObject 함수 호출이 블로킹 되었다면, Signaled 상태가 되는 순간 블로킹된 함수를 빠져 나오게 된다. 그리고 이때 자동 리셋 모드 이벤트 오브젝트라면 Non-Signaled 상태로의 변경은 자동으로 이루어 진다.

3. 이중 수동 리셋모드는 둘 이상의 쓰레드를 동시에 깨워서 실행해야 할 때 아주 좋은 도구가 될 수 있다.

Posted by JJOREG


Abstract Factory.zip

생성패턴이란? -----------------------------------------------------------------------------------------------

"생성패턴을 이용하여 객체의 인스턴스화를 무엇을? 누가? 어떻게? 언제? 생성할 것인지를 결정하는 것이다."

하지만 내가 사용하는 목적은 간단하다. 클래스에 책임 몰아주기가 가능하기 때문이다.

"이 클래스에서 종합적으로 모든 객체를 생성할꺼야." 라고 기억만 해두면 다음에는 객체가 생성되는 곳에 문제가 생겼을 때 되도록 한 클래스나 하나의 구현파일만 살펴봐도 문제가 해결될 수 있기 때문이다.


추상팩토리 --------------------------------------------------------------------------------------------------

 제 식대로 추상팩토리를 구현해 봤습니다. 

 플레이어라는 클래스는 직업, 무기, 스킬을 가지고 있고 그것을 지급받아야 합니다.

 지급받아야 되는 객체들은 모두다 추상클래스를 부모로둔 하위 클래스들입니다.

 추상 팩토리에서는 각 조합에 맞춰서 플레이어에게 지급할수 있게 합니다.

 단순히 new를 하는것이 아니라 그것을 팩토리에 맡기고 다형성을 이용하여 팩토리의 속성에 따라서 적합한 플레이어를 만들어 낼 수 있게 됩니다.


 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "stdafx.h"
#include <iostream>
 
using namespace std;
 
template <typename T>
void SAFE_DELETE(T& pointer)
{
    if(pointer)
    {
        delete pointer;
        pointer = NULL;
    }
}
 
class CJob
{
public:
    virtual ~CJob(void) {}
};
 
class CFighter : public CJob { virtual ~CFighter(void) {} };
class CMage       : public CJob { virtual ~CMage(void) {}    };
 
class CWeapon
{
public:
    virtual ~CWeapon(void) {}
};
 
class CSword : public CWeapon { virtual ~CSword(void) {} };
class CStaff : public CWeapon { virtual ~CStaff(void) {} };
 
class CSkill
{
public:
    virtual ~CSkill(void) {}
};
 
class CStrike : public CSkill        { virtual ~CStrike(void) {} };
class CMagicMissile : public CSkill { virtual ~CMagicMissile(void) {} };
 
class CAbstractFactory
{
public:
    virtual CJob*     CreJob(void) = 0;
    virtual CWeapon* CreWeapon(void) = 0;
    virtual CSkill*  CreSkill(void) = 0;
 
public:
    virtual ~CAbstractFactory(void) {}
};
 
class CMageFactory
    : public CAbstractFactory
{
    virtual CJob*     CreJob(void)        {  cout << "마법사 직업지급" << endl;     return new CMage;            }
    virtual CWeapon* CreWeapon(void)    {  cout << "스태프 지급" << endl;     return new CStaff;            }
    virtual CSkill*  CreSkill(void)        {  cout << "매직미사일을 배웠다!" << endl; return new CMagicMissile;    }    
public:
    CMageFactory(void) { cout << "유저가 마법사를 선택했다." << endl; }
    virtual ~CMageFactory(void) {}
};
 
class CFighterFactory
    : public CAbstractFactory
{
    virtual CJob*     CreJob(void)        { cout << "전사 직업지급" << endl;    return new CFighter; }
    virtual CWeapon* CreWeapon(void)    { cout << "검 지급" << endl;    return new CSword;     }
    virtual CSkill*  CreSkill(void)        { cout << "강타를 배웠다!" << endl; return new CStrike;     }    
 
public:
    CFighterFactory(void) { cout << "유저가 전사를 선택했다." << endl; }
    virtual ~CFighterFactory(void) {}
};
 
class CPlayer
{
private:
    CJob*        m_Job;
    CWeapon*    m_Weapon;
    CSkill*        m_Skill;
 
public:
    CPlayer(void) {}
 
    CPlayer(CJob* pJob, CWeapon* pWeapon, CSkill* pSkill) 
        : m_Job(pJob), m_Weapon(pWeapon), m_Skill(pSkill)
    { }
 
    ~CPlayer(void
    { SAFE_DELETE(m_Job); SAFE_DELETE(m_Weapon); SAFE_DELETE(m_Skill); }
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    cout << "*******************구분선*******************" << endl;
 
    CAbstractFactory* pFighterFactory = new CFighterFactory;
 
    CPlayer* pFighter = new CPlayer(pFighterFactory->CreJob(), pFighterFactory->CreWeapon(), pFighterFactory->CreSkill());
    SAFE_DELETE(pFighterFactory);
    SAFE_DELETE(pFighter);
 
    cout << "*******************구분선*******************" << endl;
 
    CAbstractFactory* pMageFactory = new CMageFactory;
 
    CPlayer* pMage = new CPlayer(pMageFactory->CreJob(), pMageFactory->CreWeapon(), pMageFactory->CreSkill());
    SAFE_DELETE(pMageFactory);
    SAFE_DELETE(pMage);
 
    cout << "*******************구분선*******************" << endl;
 
    return 0;
}
 

실행결과


Posted by JJOREG