2010년 7월 29일 목요일

멤버 함수를 쓰레드 함수로 만들기

오늘은 간단한 C++ 프로그래밍 기법에 대해 하나 써볼까 합니다.

간단한 기교를 부려볼 겸 클래스의 멤버함수를 쓰레드 함수로 작성하는 방법을 배워 보도록 하겠습니다.
(간단히 쓰레드 사용법도 배우고 일석이조! 야호! )

아직까진 그런 적은 없지만, 쓰레드를 돌릴 때 간간히 멤버함수를 쓰레드 함수로 제작하고플 때가 있더군요.
혹, 그런 분들을 위해 알려 드리겠습니다.
 
 class TestClass {

     INT B;

     VOID TestFunction( INT A ) { B = A };                       //이 함수를 쓰레드로 돌리고자 합니다.
     VOID Start();                                                          //이 함수에서 TestFunction을 호출하지요.

};

 
 Start() 멤버 함수에서 TestFunction()을 쓰레드로 돌리고자 한다고 해보죠.

 VOID TestClass ::Start() {

       HANDLE hThread = ( HANDLE ) __beginthread( NULL, 0, &TestFunction, NULL, NULL, NULL );
       // ........ 무엇가의 작업을 하고.

       WaitForSingleObject( hThread, INFINITE );
       CloseHandle( hThread );
}

  
물론 안됩니다. 쓰레드로 돌아갈  함수는 정적으로 선언되어야 하며 정적 함수여야 하죠. 따라서,
 
 class TestClass {

     static VOID WINAPI TestFunction( INT A );                    // 이제 원래 의도대로 이 함수를 정적 함수로 제작합니다.
     VOID Start();

};

  역시 물론 안됩니다. 직접 닥쳐보시면 알겠지만, 우리가 돌리고자 했던 TestFunction 함수에서는 B라는 비정적 멤버를 참조하고 있습니다.

결국은 다른 방법을 찾아야 합니다.

 class TestClass {

     VOID TestFunction( INT A );                                             //다시 원래대로 돌리고
     static VOID WINAPI TestFunctionThread( LPVOID );            //대신 쓰레드가 돌아갈 정적 함수를 만듭니다.
     VOID Start();

};

VOID Start() {

       HANDLE hThread = ( HANDLE ) __beginthread( NULL, 0, &TestFunctionThread, this, NULL, NULL );
       // ........ 무엇가의 작업을 하고.

       WaitForSingleObject( hThread, INFINITE );
       CloseHandle( hThread );

}

VOID WINAPI TestFunctionThread( LPVOID p ) {
      (  (TestClass* ) p )->TestFunction( 3 );
}


자, 위 예를 통해 해결했습니다. 포인터. 즉 동적 호출을 통해서 정적 멤버 함수를 호출하였습니다.

TestFunction의 인자 값도 동적으로 주고 싶다면,
 
 struct Arg {
      TestClass* p;
       INT A;
};

VOID Start() {

        Arg arg = { this, 3 };

       HANDLE hThread = ( HANDLE ) __beginthread( NULL, 0, &TestFunctionThread, &arg, NULL, NULL );
       // ........ 무엇가의 작업을 하고.

       WaitForSingleObject( hThread, INFINITE );
       CloseHandle( hThread );

}

VOID WINAPI TestFunctionThread( LPVOID p ) {
      Arg* pArg = ( Arg* ) p;
      pArg->p->TestFunction( p->A );     
}
 



2010년 4월 15일 목요일

삼항연산자 사용

삼항연산자

 

삼항연산자는 연산을 위해서 3개의 항이 필요함을 의미하는 것으로
if 문을 축소시킨 형태가 있다. 예1) 과 예2)는 같은 결과를 나타내며, 같은 의미이다.

실제 속도에 있어서는 예1)이 미미하지만 더 빠르게 실행이 된다. 하지만,

코드가 알아보기 어려운 점이 좀 있다... 눈에  잘 안들어오는..

 

 

예1)

    var a = 10,  b = 11;
    var str = a > b ? "a가 b보다 크다" : "a가 b보다 작다";
    trace(str);

 

 

첫번째 프레임에 위 소스를 넣고 확인해보면 된다.

a 와 b 의 값을 바꾸어서 실행해보기도 한다.

 

a>b 가 만족하면 : 의 앞에것을 실행하고 만족하지 않으면 후자를 실행하라는 의미이다.

이것은 if, else 문과 같다.

 

예2)

var a = 10,  b = 11;

 

if(a > b){

    str = "a가 b보다 크다";

}else{

    str = "b가 a보다 크다";

}

    trace(str); 

2010년 3월 30일 화요일

MFC에서의 멀티쓰레드(Multithread)

MFC에서의 Multithread
 
OS는 구분하지 않지만 MFC는 사용자 편의를 위하여 두 가지 형태로 지원
 
1.     Worker thread
2.     User Interface thread
 
Worker thread
 
::AfxBeginThread() 함수를 이용
 
CWinThread* ::AfxBeginThread(
       AFX_THREADPROC pfnThreadProc,
       LPVOID pParam,
       int nPriority = THREAD_PRIORITY_NORMAL, // 기본적으로 주 Process와 동일
       UINT nStackSize = 0,
       DWORD dwCreateFlags = 0,                      // 0 또는 CREATE_SUSPENDED
       LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
);
 
우선 Thread를 이용할 함수를 먼저 정의한다
 
UINT ThreadFunc(LPVOID pParam)
{
       int option = (int)pParam;
       …
}
 
만약 인자가 많은 경우에는
 
typedef struct tagPARAMS
{
       ...
} PARAMS;
 
와 같이 한 후에
 
PARAMS *pParams = new PARAMS;
CWinThread *pThread = ::AfxBeginThread(ThreadFunc, &pParams);
 
와 같이 하고
 
UINT ThreadFunc(LPVOID pParam)
{
       PARAMS *pThreadParams = (PARAMS *)pParam;
       ...
       delete pThreadParams;
 
       return 0;
}
 
와 같이 사용하면 된다.
 
Thread를 잠시 중지시키고 싶을 때는 주 Process에서
 
pThread->SuspendThread();
 
다시 돌리고 싶을 때는 주 Process에서
 
pThread->ResumeThread();
 
와 같이 하면 된다.(Thread 자신이 호출할 수는 없다.)
또는 경우에 따라서는
 
Sleep(2000);
 
과 같이 사용할 수도 있는데 이 경우는 제어권을 다른 Process에 넘겨 주게 된다.
 
Sleep(0);
 
와 같이 할 경우에는 우선 순위가 높거나 같은 Process에 넘겨 주고 우선 순위가 높거나
같은 Process가 없을 경우에는 아무 일도 생기지 않는다.
 
Thread를 종료시키고 싶을 때는 TerminateThread() 함수를 사용하면 되는데 이 경우 Thread 함수가
내부 정리를 하지 못할 수가 있기 때문에 다음과 같은 방법이 많이 사용된다.
 
static BOOL bContinue = TRUE;
CWinThread *pThread = ::AfxBeginThread(ThreadFunc, &bContinue);

 
UINT ThreadPrintNum(LPVOID pParam)
{
       BOOL *pbContinue = (BOOL *)pParam;
       while ( *pbContinue )
       {
             …
       }
       return 0;
}
 
와 같이 하고 bContinue 값을 FALSE로 하면 Thread 함수가 종료된다.
 
Thread가 완전히 종료된 것을 확신해야 하는 경우에는
 
if ( ::WaitForSingleObject(pThread->m_hThread, INFINITE) )
{
       // 이곳은쓰레드가확실히종료된상태임
}
 
와 같이 하면 된다. Thread가 죽어 버려서 먹통이 되는 경우까지 대비하려면
 
DWORD result;
result = ::WaitForSingleObject(pThread->m_hThread, 1000);   // 1초기다림
if ( result == WAIT_OBJECT_0 )
{
       // 이곳은쓰레드가확실히종료된상태임
}
else if ( result == WAIT_TIMEOUT )
{
       // 1초가지나도쓰레드가종료되지않은상태
}
 
이 방법을 사용해야 한다. 어떤 Thread가 현재 실행 중인지 알고 싶을 때는
 
if ( ::WaitForSingleObject(pThread->m_hThread, 0 ) == WAIT_TIMEOUT )
{
       // pThread 실행중
}
else
{
       // pThread가실행중이아님
}
 
와 같이 하면 된다.
 
User Interface Thread
 
User interface thread는 그 자체로 윈도우와 메시지 루프를 가지고 있다.
 
class CUIThread : public CWinThread
{
       DECLARE_DYNCREATE(CUIThread)
 
public:
       virtual BOOL InitInstance();
};
 
이 User interface thread는 독자의 윈도우도 가질 수 있다. 일반적으로 전용 Dialog를 띄워
Thread를 처리하는 경우가 많으므로 이 User Dialog를 CMyDialog라고 이름 지었다고 가정하면
 
IMPLEMENT_DYNCREATE(CUIThread, CWinThread)
 
BOOL CUIThread::InitInstance()
{
       m_pMainWnd = new CMyDialog;
       m_pMainWnd->ShowWindow(SW_SHOW);
       m_pMainWnd->UpdateWindow();
       return TRUE;
}
 
와 같이 CMyDialog를 Thread로 띄울 수 있다. 그 다음
 
CWinThread *pThread = ::AfxBeginThread(RUNTIME_CLASS(CUIThread));
 
와 같이 하면 MFC가 알아서 CUIThread를 생성해서 그 포인터를 pThread에 넘겨 준다.
 
아래 예제에는 CMyDialog를 띄우고 주 Process는 사용자의
입력을 기다린다. Dialog의 Design 및 생성은 별도로 이야기하지 않는다. 아래 예제를 사용하기 위해서는
CMyDialog를 만들고 ID를 IDD_MYDIALOG라고 가정하면 CMyDialog의 생성자에 다음과 같이 추가해야 제대로 동작한다.
 
CMyDialog::CMyDialog(CWnd* pParent /*=NULL*/)
       : CDialog(CMyDialog::IDD, pParent)
{
       Create(IDD_MYDIALOG, NULL);
}
 
이제 완전히 별도로 동작하는(Thread로 동작하는) 윈도우를 하나 가지는 것이다. 만약 이것을 Dialog가 아닌
FrameWnd라고 해도 거의 똑같다. 다만 위에서도 언급했듯이 Thread를 이용할 때는 Dialog가 더 일반적일 것이다.
Worker thread에 비해 훨씬 더 많은 기능을 하는 것을 알게 되었을 것이다.
 
나머지 것들은 위의 Worker Thread에 있는 내용과 동일하다.
 
만약 여러 개의 CUIThread 를 여러 개 만들려고 한다면
 
CWinThread *pThread[5];
for ( int i = 0; i < 5; i++ )
       m_pThread[i] = ::AfxBeginThread(RUNTIME_CLASS(CUIThread));
 
와 같이 하면 5개의 Thread가 생성된다.
 
Program Execution Priority(프로그램 실행 우선순위)
 
Thread는 0~31까지의 priority를 가질 수 있다.
 
프로그램의 priority는
 
BOOL SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass);
 
함수를 이용해서 조정할 수 있다. 첫 번째 인자 hProcess는 ::AfxGetInstanceHandle()로 얻으면 된다.
 
dwPriorityClass
Execution Priority
Description

DLE_PRIORITY_CLASS
CPU가 IDLE일 때만 사용 가능

ORMAL_PRIORITY_CLASS
보통

IGH_PRIORITY_CLASS
높은 우선 순위

EALTIME_PRIORITY_CLASS
최상위의 우선순위


Thread Execution Priority(쓰레드 실행 우선순위)
 
::AfxBeginThread() 함수의 nPriority를 통해서 설정하거나 CWinThread::SetThreadPriority 를 사용해 설정할 수 있다.
 
BOOL SetThreadPriority(HANDLE hThread, int nPriority);
 
nPriority
Execution Priority
Description

HREAD_PRIORITY_IDLE
REALTIME_PRIORITY_CLASS의 경우 16, 그 외에는 1

HREAD_PRIORITY_LOWEST
프로세스의 우선순위보다 2단계 낮은 우선순위를 가진다

HREAD_PRIORITY_BELOW_NORMAL
프로세스의 우선순위보다 1단계 낮은 우선순위를 가진다

HREAD_PRIORITY_NORMAL
프로세스의 우선순위가 같은 우선순위

HREAD_PRIORITY_ABOVE_NORMAL
프로세스의 우선순위보다 1단계 높은 우선순위를 가진다

HREAD_PRIORITY_HIGHEST
프로세스의 우선순위보다 2단계 높은 우선순위를 가진다

HREAD_PRIORITY_CRITICAL
REALTIME_PRIORITY_CLAS의 경우 31 그 외에는 16


프로그래머가 우선순위를 조정해도 Windows Scheduler가 상황에 맞게 조정하기 때문에 우선순위는
생각하고 조금 다를 수 있다.
 
Thread & Memory
 
각 Thread의 지역 변수는 모두 별도로 Stack을 만들고 Local Variable들을 관리하기 때문에 위의
 
CWinThread *pThread[5];
for ( int i = 0; i < 5; i++ )
       m_pThread[i] = ::AfxBeginThread(RUNTIME_CLASS(CUIThread));
 
와 같은 경우에도 각 Thread가 다른 Thread를 침범하는 일은 없다.
 
이 쯤에서 끝났나 싶겠지만… 아직 갈 길이 멀다.
Critical section, Mutex, Semaphore 같은 것들은 다음에…
 
Multithreading synchronization(멀티쓰레드의 동기화) => http://blog.naver.com/xtelite/50023359879
 
프로그램

Worker thread
 
#include "stdafx.h"
#include "console.h"
 
#include <iostream>
 
using namespace std;
 
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
 
// The one and only application object
CWinApp theApp;
 
using namespace std;
 
UINT ThreadPrintNum(LPVOID pParam);
 
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
       int nRetCode = 0;
 
       // initialize MFC and print and error on failure
       if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
       {
             _tprintf(_T("Fatal Error: MFC initialization failed\n"));
             return 1;
       }
 
       static BOOL bContinue = TRUE;
       CWinThread *pThread = ::AfxBeginThread(ThreadPrintNum, &bContinue);
 
       int count = 0;
       while ( count < 1000 )
       {
             count++;
       }
 
       Sleep(1000);
       pThread->SuspendThread();
       cout << "Thread suspended. Waiting for 2 seconds" << endl;
 
       Sleep(2000);
       cout << "Thread resumed" << endl;
       pThread->ResumeThread();
 
       cout << "Quit thread" << endl;
       bContinue = FALSE;
       Sleep(100);
 
       return nRetCode;
}
 
// 쓰레드함수
UINT ThreadPrintNum(LPVOID pParam)
{
       BOOL *pbContinue = (BOOL *)pParam;
       int count = 0;
       while ( *pbContinue )
       {
             count++;
       }
       cout << "Exit thread" << endl;
       return 0;
}
 
User interface thread
 
#include "stdafx.h"
#include "console.h"
 
#include "MyDialog.h"
 
#include <cstdlib>
 
using namespace std;
 
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
 
// The one and only application object
CWinApp theApp;
 
using namespace std;
 
class CUIThread : public CWinThread
{
       DECLARE_DYNCREATE(CUIThread)
 
public:
       virtual BOOL InitInstance();
};
 
IMPLEMENT_DYNCREATE(CUIThread, CWinThread)
 
BOOL CUIThread::InitInstance()
{
       m_pMainWnd = new CMyDialog;
       m_pMainWnd->ShowWindow(SW_SHOW);
       m_pMainWnd->UpdateWindow();
       return TRUE;
}
 
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
       int nRetCode = 0;
 
       // initialize MFC and print and error on failure
       if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
       {
             _tprintf(_T("Fatal Error: MFC initialization failed\n"));
             return 1;
       }
 
       CWinThread *pThread = ::AfxBeginThread(RUNTIME_CLASS(CUIThread));
      
       system("pause");
 
       return nRetCode;
}


출처 : "http://system.tistory.com/entry/멀티-쓰레딩"

2010년 1월 30일 토요일

좌충우돌 구미 공장 견학기

2일간의 일정으로 구미 공장에 다녀왔다.

타이틀은 거창하게 출장이었는데... 신입이다보니 역시 그냥 견학 정도로 만족해야 할 것 같다.

같은 파트 분들 이번에 많이 인사도 드렸고,

내가 하게될 일들 설명도 듣고, 장비들도 직접 만져보고 도면도 익히고 하다보니

아~~ 뭔가 실감이 난다.... ^^;;;

공장은 연구소쪽이랑은 분위기가 완전히 다르다.

다들 작업복 입고 분주하게 돌아다니는 모습.... 게다가 근무시간과 휴식시간이 칼같이 분리되어 있다.

일하다가 적당히 쉬고 싶으면 커피한잔 하면서 쉬는 연구소랑은 전혀 다른 듯... -_-;;;

뭔가 굉장히 조직적이고 일사분란함을 느낄 수 있었다. 게다가 엄청 넓고 사람도 엄청 많고~~ ^^

하지만 사람들은 굉장히 여유롭다. 연구소 보다 스트레스는 덜 한건지..... ㅎㅎ

퇴근도 거의 칼 퇴근.... 저녁먹고 공장 내려가봤는데.... 몇명 빼놓고는 전부 다 집에로 ㄱㄱㅆ

24시간 가동하는 라인이 있는 것도 아니고... 한꺼번에 몇천대씩 생산해나는 기계가 있는 것도 아니니..

뭐 여유로울 것 같긴 하다 ㅎㅎㅎㅎ

나름 재미도 있고, 힘들어도 하고 싶다는 생각이 드는 일인 것 같다.

아.... 다행이다..... 즐기면서 할 수 있는 일을 찾은 것 같아서.... 히힛

2010년 1월 24일 일요일

두근두근 첫 출근~♡

사실 회사 생활은 처음이다.

유일한 경험이라고 한다면 연수원에서 지난 2주간 받았던 교육이 전부랄까?

마치 육군 훈련소에서 교육을 모두 다 마치고,

자대에서 데려가기를 기다리는 그런 심정인거 같다....

내가 배치받을 부서는? 그리고 내가 하게될 일은?

그 일을 함께하게될 사람들은???

모든게 궁금하고 어색하고 그래서 약간의 두려움이 있긴 하지만.....

왠지 기다려지는..... 두근두근거림...... 정말 오랫만인듯..... ^^

오늘 백화점에 들렀다가 세일 마지막 날이라는 말에

출퇴근하면서 필요할 것 같은 가방을 하나 질렀다.

이렇게 비싼 가방 학생때는 갖고 싶어 하지도 않았고 사지도 않았었는데.....

왠지 사회생활 시작한다니깐 하나쯤은 갖고 싶어졌나보다..... 후후;;;;;

그래... 내일은 너와 함께 새롭게 출발하는거야... ㅋㅋㅋ

2010년 1월 18일 월요일

신입사원 연수 그리고 임시퇴소

LIG 넥스원에 최종합격 통보를 받고,

11일 드디어 연수원에 입소식을 거치며 신입사원 타이틀을 달았다.

그리고 일주일의 교육.......

사실 처음 입소하기 전에는 이 많은 교육들이 다 필요할까... 재미 없을 거 같기도하고...

귀찮다는 생각도 들긴 했었다.

그런데 막상 입소하고 나서 사람들을 만나고 활동을 진행해 나가면서 나도 모르게 점점

빠져들고 말았다. 회사에 대해 알고 사람에 대해 알아가면서 정이 들었나 보다.

그래도 건강관리는 잘해놨어야 하는건데.....

연수 첫주의 마지막날 야간행군 30km를 거치면서 몸에 고장이 났다. 감기 몸살....... 두둥.... -_-

사실 며칠 전부터 몸이 안좋았었는데... 행군을 가지 말았어야 할 것을... 내가 우겨서 참석한게

화근이었나보다.... 쩝

감기약을 먹어도 열이 떨어지지가 않아서 응급실에 주사를 맞으러 갔는데....

체온이 39.8도란다... 발열이 있으니 신종플루일 가능성이 있으니 타미플루 복용하고

거첨병원가서 확진검사를 받으라는데.... 아~~ 하늘이 노래진다......

역시 걱정했던데로 퇴소 조치가 내려졌고.....

지금 이 시간.... 난 집에 있다. ㅠ.ㅠ

오후에는 백병원에 다녀왔다.

확진검사 받으러.... 신종플루의 기세가 한층 누그러들었다고 생각했는데,

병원에는 여전히 많은 사람들로 북적인다.

휴~~ 제발 양성 반응이 안나왔으면 좋겠는데......

하루빨리 연수원에 들어가서 나머지 교육이라도 제대로 받았으면 하는 소망이..... ^^;;

어쨌든 결론은 건강 관리 잘합시다!!!