mfc_Thread - 8BitsCoding/RobotMentor GitHub Wiki

(์ฃผ์˜)

MFC์—์„œ GetDlgItem๊ณผ ๊ฐ™์€ Temporary ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

Thread๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๋™์•ˆ Main Thread์—์„œ๋Š” ์ž„์‹œ๊ฐ์ฒด(GetDlgItem์—์„œ ๋ฐ˜ํ™˜๋œ ๊ฐ์ฒด)์˜ ๋ฉ”๋ชจ๋ฆฌ๋Š” ๋ชจ๋‘ ์ง€์šฐ๊ธฐ ๋•Œ๋ฌธ!


Thread๊ฐ€ ํ•„์š”ํ•œ Example

ํ•˜๋‚˜์˜ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์ž‘์—…์„ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž.

// Button Click
CString str;
int index;

for(int i = 0; i < 10000; i++)
{
    str.Format(L"item %05d", i);
    index = m_data_listbox.InsertString(-1, str);
    m_data_listbox.SetCurSel(index);
}

์œ„ for๋ฌธ์ด ๋ชจ๋‘ ๋™์ž‘ํ•˜๊ธฐ ์ „ ๋ฉ”์ธ ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ์›€์ง์ด๊ฑฐ๋‚˜ ์ถ”๊ฐ€ ํด๋ฆญ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

Thread๋ฅผ ํ†ตํ•˜์—ฌ ๊ฐœ์„ ํ•ด ๋ณด์ž.


Thread ์ƒ์„ฑ

DWORD WINAPI InsertItemToList(void* ap_data)
{
    CString str;
    int index;

    for(int i = 0; i < 10000; i++)
    {
        str.Format(L"item %05d", i);
        index = ap_data->InsertString(-1, str);
        ap_data->SetCurSel(index);
    }

    return 0;
}
HANDLE h_thread;
h_thread = CreateThread(NULL, 0, InsertItemToList, &m_data_listbox, 0, NULL);

if(h_thread != NULL) {
    // Thread ์ƒ์„ฑ
    
}

CreateThread์— ๋Œ€ํ•œ ์„ค๋ช…

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES   lpThreadAttributes,
  SIZE_T                  dwStackSize,
  LPTHREAD_START_ROUTINE  lpStartAddress,
  __drv_aliasesMem LPVOID lpParameter,
  DWORD                   dwCreationFlags,
  LPDWORD                 lpThreadId
);
  • lpThreadAttributes : ์‚ฌ์šฉ์ž ๊ณ„์ • ์ปจํŠธ๋กค, ๊ด€๋ฆฌ์ž๋ชจ๋“œ, ์ผ๋ฐ˜์‚ฌ์šฉ์ž ๋ชจ๋“œ ๋“ฑ
  • dwStackSize : ๊ฐ Thread์˜ Stack Size, 0์œผ๋กœ ๋‘๋ฉด 1MB (๋ณดํ†ต 1MB์ž„) 32bit ์šด์˜์ฒด์ œ ๊ธฐ์ค€์œผ๋กœ ์ตœ๋Œ€ ์‚ฌ์šฉ๊ฐ€๋Šฅ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ 4GB์ด๊ณ  2GB๋Š” OS์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ์— 2GB ์ค‘ 1700MB ์ •๋„๋งŒ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅ ๋”ฐ๋ผ์„œ StackSize๋ฅผ 1MB๋กœ ๋‘๋ฉด Thread 1700๊ฐœ ์ •๋„์‚ฌ์šฉ์ด ๊ฐ€๋Šฅ
  • lpStartAddress : ThreadFunc ์ฃผ์†Œ
  • lpParameter : Thread์— ๋„˜๊ธธ ์ธ์ž
  • dwCreationFlags : Thread ์ƒ์„ฑ ์‹œ Flag ์ง€์ •
  • lpThreadId : ๋ฐ˜ํ™˜๋˜๋Š” Thread ID

์ •๋ง ์‰ฝ๋„ค?? ๋ญ๊ฐ€ ๋ฌธ์ œ์ง€???

  1. Main Thread๊ฐ€ ์ข…๋ฃŒ๋œ๋‹ค๊ณ  ๋‚ด๋ถ€ Thread๊ฐ€ ๋ชจ๋‘ ์ข…๋ฃŒ๋˜๋Š”๊ฒƒ์ด ์•„๋‹ˆ๋‹ค!

For๋ฌธ์ด ๋ชจ๋‘ ๋Œ์•„๊ฐ€๊ธฐ ์ „ MainWindow๋ฅผ ์ฃฝ์ด๋ฉด?? -> Thread๋Š” ๊ทธ๋Œ€๋กœ ์‚ด์•„์žˆ๋Š”๋‹ค.

// Dlg.h
HANDLE mh_thread = NULL;
mh_thread = CreateThread(NULL, 0, InsertItemToList, &m_data_listbox, 0, NULL);

if(mh_thread != NULL) {
    // Thread ์ƒ์„ฑ
    
}

ํด๋ž˜์Šค ๋งˆ๋ฒ•์‚ฌ -> WM_DESTROY ์ƒ์„ฑ

// OnDestroy()
CDialogEx::OnDestroy();

if(mh_thread != NULL)
{
    TerminateThread(mh_thread, 0);
}

์œ„ ์ฒ˜๋Ÿผ ํ•˜๋ฉด ๋ ๊นŒ??

๋ฌธ์ œ๋Š” Thread ๋‚ด๋ถ€์—์„œ ๋™์  ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํšŒ์ˆ˜ํ•˜์ง€ ์•Š๊ณ  ๋น„์ •์ƒ ์ข…๋ฃŒ๋ฅผ ํ•ด๋ฒ„๋ฆฌ๊ฒŒ ๋œ๋‹ค.

์ด๋Ÿฐ ๋น„์ •์ƒ ์ข…๋ฃŒ์˜ ๊ฐ€์žฅ ํฐ ๋ฌธ์ œ์ ์€ Mutex์˜์—ญ์„ ์„ค์ •ํ•˜๋ฉด ๋น„์ •์ƒ ์ข…๋ฃŒ๋œ Mutex์— ์˜ํ•ด์„œ lock์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค.

์ •๋ง ๊ธ‰ํ•˜๊ฒŒ ์ผ์„ ์ฒ˜๋ฆฌํ•ด์•ผํ• ๋•Œ TerminateThread๋ฅผ ์“ฐ์ž...

๊ทธ๋Ÿผ ์–ด์ฉŒ๋ผ๊ณ ?

EVENT๋ฅผ ์ด์šฉํ•ด๋ณด์ž.

// Dlg.h
struct ThreadData
{
    CListBox* p_list_box;
    HANDLE h_kill_event;
    HANDLE h_thread;
};

private:
    ThreadData m_thread_data;
// OnInitDialog
m_thread_data.p_list_box = &m_data_list;
m_thread_data.h_kill_event = CreateEvent(NULL, 1, 0, L"Tips001");
m_thread_data.h_thread = NULL;

์ฝ”๋“œ์„ค๋ช… (CreateEvent)

HANDLE CreateEventA(
  LPSECURITY_ATTRIBUTES lpEventAttributes,
  BOOL                  bManualReset,
  BOOL                  bInitialState,
  LPCSTR                lpName
);
  • lpEventAttributes : ์‚ฌ์šฉ์ž ๊ณ„์ • ์ปจํŠธ๋กค, ๊ด€๋ฆฌ์ž๋ชจ๋“œ, ์ผ๋ฐ˜์‚ฌ์šฉ์ž ๋ชจ๋“œ ๋“ฑ
  • bManualReset : 1(ManualReset)๋กœ ๋‘๋ฉด ๋‚ด๊ฐ€ SetEventํ•˜๋ฉด Set ์„ค์ • / 0์œผ๋กœ ๋‘๋ฉด ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด CloseEvent
  • bInitialState : ์ฒ˜์Œ์— 0์œผ๋กœ ์‹œ์ž‘ํ• ์ง€ 1๋กœ ์‹œ์ž‘ํ• ์ง€, 0์œผ๋กœ ๋‘๋ฉด 0์œผ๋กœ ์‹œ์ž‘
  • lpName : ์ด๋ฒคํŠธ๊ฐ์ฒด ์ด๋ฆ„, ์ด๋ฒคํŠธ ์ด๋ฆ„์„ ์•Œ๋ฉด OpenEvent()๋ฅผ ํ†ตํ•ด์„œ ์ด๋ฒคํŠธ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค.
m_thread_data.h_thread = CreateThread(NULL, 0, InsertItemToList, &m_thread_data, 0, NULL);

if(m_thread_data.h_thread != NULL) {
    // Thread ์ƒ์„ฑ
    
}
DWORD WINAPI InsertItemToList(void* ap_data)
{
    ThreadData * p_data = (ThreadData *)ap_data;

    CString str;
    int index;

    for(int i = 0; i < 10000; i++)
    {
        if(WaitForSingleObject(p_data->h_kill_event, 1) == WAIT_OBJECT_0)
        {
            // Event๊ฐ€ Set ์ƒํƒœ์ด๋ฉด == WAIT_OBJECT_0
            // Event๊ฐ€ Set ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ฉด == WAIT_TIMEOUT
            break;
        }
        str.Format(L"item %05d", i);
        index = p_data->p_list_box->InsertString(-1, str);
        p_data->p_list_box->SetCurSel(index);
    }

    CloseHandle(p_data->h_thread);
    p_data->h_thread = NULL;

    return 0;
}
// OnDestroy()
CDialogEx::OnDestroy();

if(m_thread_data.h_thread != NULL)
{
    SetEvent(m_thread_data.h_kill_event);
    while(m_thread_data.h_thread != NULL);
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ์ ์ด ๋ฐœ์ƒ

while(m_thread_data.h_thread != NULL); ์—์„œ๋Š” Thread๊ฐ€ ์ฃฝ๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๊ณ 

Thread์˜ index = p_data->p_list_box->InsertString(-1, str);๋Š” Main Thread์—์„œ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌํ›„ ์‘๋‹ต์„ ์ฃผ๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉด์„œ ๋ฐ๋“œ๋ฝ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.


ํ•ด๊ฒฐ๋ฐฉ์•ˆ??

// OnDestroy()
CDialogEx::OnDestroy();

if(m_thread_data.h_thread != NULL)
{
    SetEvent(m_thread_data.h_kill_event);

    MSG msg;

    while(m_thread_data.h_thread != NULL && GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessge(&msg);
        DispatchMessage(&msg);
    }
}

๋ฉ”์‹œ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ตฌ๋ฌธ์„ ๋„ฃ์–ด์ค€๋‹ค.


ํ•˜์ง€๋งŒ ์ด๋ฒˆ ์˜ˆ์ œ์˜ ์น˜๋ช…์  ๋ฌธ์ œ์ ์ด ์žˆ์Œ.

Thread์—์„œ p_data->p_list_box->InsertString(-1, str); ๋ฉ”์ธ Thread์˜ ๋™์ž‘์„ ์š”๊ตฌํ•˜๊ฒŒ ๋˜๋Š”๋ฐ,

์ด๋ ‡๊ฒŒ ๋™์ž‘ํ•  ๊ฒฝ์šฐ Thread๊ฐ€ ๋ช‡๊ฐœ ์•ˆ๋˜๋ฉด ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋‚˜

Thread์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์•„ ์งˆ์ˆ˜๋ก Main Thread์˜ ๋ถ€ํ•˜๊ฐ€ ์ปค์ง€๊ฒŒ ๋œ๋‹ค.

๋‹ค์Œ๊ฐ•์ขŒ์—์„œ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ๋ชจ์ƒ‰ํ•ด๋ณธ๋‹ค.