본문 바로가기

프로그램언어/C++

스레드

_beginthreadex() 함수 : 스래스 생성하기

uintptr_t _beginthreadex(       // 스레드 핸들 값 반환
    void          *security,        // SECURITY_ATTRIBUTES 구조체의 포인터 변수, NULL을 사용
    unsigned    stack_size,      // 스레드를 위한 스택의 크기, 0을 사용
    unsigned   ( *start_address )( void * ),   // 스레드를 실행할 함수 이름
    void         *arglist,          // 스레드 함수에 전달될 매개변수 주소
    unsigned   initflag,          // 스레드 상태 지정 값으로 실행하기 위해 0을 사용
    unsigned   *thrdaddr       // 스레드 ID를 받기 위한 32비트 포인터 변수, NULL을 사용
);

 

_endthreadex() 함수 : 스레드 종료하기

void _endthreadex(
    unsigned retval       // 반환을 원하는 값
);

 

CloseHandle() 함수 : 스레드 정리하기

BOOL WINAPI CloseHandle(
    HANDLE hObject
);

 

멀티스레드 프로그램 작성하기

#include <windows.h>

#include <TCHAR.H>

#include <process.h>

#include <time.h>

HWND hwnd; // WinMain() 함수의 지역변수를 전역변수로 전환

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)

{

    MSG msg;

    WNDCLASS WndClass;

    WndClass.style = CS_HREDRAW | CS_VREDRAW;

    WndClass.lpfnWndProc = WndProc;

    WndClass.cbClsExtra= 0;

    WndClass.cbWndExtra= 0;

    WndClass.hInstance = hInstance;

    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);

    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);

    WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

    WndClass.lpszMenuName = NULL;

    WndClass.lpszClassName = _T("Window Class Name");

    RegisterClass(&WndClass);

    hwnd = CreateWindow(_T("Window Class Name"), _T("Window Title Name"), WS_OVERLAPPEDWINDOW,

        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL );

    ShowWindow(hwnd, nCmdShow);

    UpdateWindow(hwnd);

    while(GetMessage(&msg, NULL, 0, 0))

    {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }

    return (int)msg.wParam;

}

 

void ThreadProc()

{

    HDC hdc;

    int i;

    srand((unsigned)time(0));

    hdc = GetDC(hwnd);

    SelectObject(hdc, CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256) ) );

                           // 색상을 가지는 브러시

    for (i = 0; i <= 10; i++)

    {

        int num;

        num = rand()%500;     // 0 ~ 499까지의 임의의 수

        Sleep(3000);              // 3초 멈춤

        Rectangle(hdc, 0, 0, 20, num); 

    }

    ReleaseDC(hwnd, hdc);

    return;

}

 

#define THREAD_NUM 10

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

    static HANDLE hThread[THREAD_NUM];

    int i;

    switch (iMsg)

    {

    case WM_LBUTTONDOWN:

        for (i = 0; i < THREAD_NUM; i++)        // THREAD_NUM 10

        {

            hThread[i] = (HANDLE)_beginthreadex(NULL, 0, (unsigned int(__stdcall *)(void *))ThreadProc, NULL0, NULL);
            // _beginthreadex함수를 이용해 ThreadProc()함수 호출 (스레드함수이름, 함수에 전달될 변수의 주소)

            Sleep(2000);

        }

        break;

    case WM_DESTROY:

        for (i = 0; i < THREAD_NUM; i++)

            CloseHandle(hThread[i]);

        PostQuitMessage(0);

        return 0;

    }

    return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

실행 결과]

 

 

스레드 함수에 매개변수 전달하기

void ThreadProc(void *arg)

{

    HDC hdc;

    int i;

    int xPos = *((int *)arg);

    srand((unsigned)time(0));

    hdc = GetDC(hwnd);

    SelectObject(hdc, CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256) ) );

    for(i = 0; i <= 10; i++)

    {

        int num;

        num = rand()%500;

        Sleep(3000);

        Rectangle(hdc, xPos, 0, xPos+20, num);

    }

    ReleaseDC(hwnd, hdc);

    return;

}

 

#define THREAD_NUM 10

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

    static HANDLE hThread[THREAD_NUM];

    static int xPos[THREAD_NUM];

    int i;

 

    switch (iMsg)

    { 

    case WM_CREATE:

        for (i = 0; i < THREAD_NUM; i++)

            xPos[i] = i*100;

        break;

    case WM_LBUTTONDOWN:

        for (i = 0; i<THREAD_NUM; i++)

        {

            hThread[i] = (HANDLE)_beginthreadex(NULL, 0, (unsigned int(__stdcall *)(void *))ThreadProc,
                (void *)&xPos[i], 0, NULL );
          // _beginthreadex함수를 이용해 ThreadProc()함수 호출 (스레드함수이름, 함수에 전달될 변수의 주소)

            Sleep(2000);

        } 

        break;

    case WM_DESTROY:

        for (i = 0; i < THREAD_NUM; i++)

            CloseHandle(hThread[i]);

        PostQuitMessage(0);

        return 0;

    }

    return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

실행 결과]

 

스레드 동기화하기

전역번수의 영향을 알아보기

int max;

void ThreadProc(void *arg)

{

    HDC hdc;

    int i;

    int xPos = *((int *)arg);

    srand((unsigned)time(0));

    hdc = GetDC(hwnd);

    SelectObject(hdc, CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256) ) );

 

    for(i = 0; i <= 10; i++)

    {

        int num;

        num = rand() % 500;

        if (num > max)

        {

            Sleep(3000);

            max = num;

            Rectangle(hdc, xPos, 0, xPos+20, num);

        }

    }

    ReleaseDC(hwnd, hdc);

    return;

}

 

#define THREAD_NUM 10

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

    static HANDLE hThread[THREAD_NUM];

    static int xPos[THREAD_NUM];

    int i;

 

    switch (iMsg)

    {

    case WM_CREATE:

        for (i = 0; i < THREAD_NUM; i++)

            xPos[i] = i*100;

        max = 0;

        break;

    case WM_LBUTTONDOWN:

        for (i = 0; i < THREAD_NUM; i++)

        {

            hThread[i] = (HANDLE)_beginthreadex(NULL, 0, (unsigned int(__stdcall *)(void *))ThreadProc,

                (void *)&xPos[i], 0, NULL );

            Sleep(2000);

        }

        break;

    case WM_DESTROY:

        for (i = 0; i < THREAD_NUM; i++)

            CloseHandle(hThread[i]);

        PostQuitMessage(0);

        return 0;

    }

    return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

실행 결과]

 

CreateEvent() 함수 : 이벤트 생성하기

HANDLE CreateEvent(                                      // 이벤트 핸들 값 반환
    LPSECURITY_ATTRIBUTES   lpEventAttributes,    // 보안속성, 보통은 NULL 사용 
    BOOL      bManualReset,     // 시그널/넌시그널 수동 변환 설정
    BOOL      bInitialState,        // 초기상태(TRUE : 시그널 상태로 이벤트 생성, FALSE : 넌시그널 상태로 이벤트 생성)
    LPTSTR    lpName              // 이벤트 이름, 보통은 NULL 사용
);

시그널 이란: 특정 이벤트가 발생했을때 신호를 보내서 알려주는걸 시그널이라고 한다.

시그널 : 스레드나 프로세스가 종료된 상태

넌 시그널 : 스레드나 프로세스가 실행중인 상태

 

SetEvent() 함수 : 이벤트 설정하기

SetEvent(                     // 이벤트 시그널 상태로 변환
   HANDLE hEvent         // 이벤트 핸들
);

 

ResetEvent() 함수 : 이벤트 재설정(리셋)하기

BOOL ResetEvent(             // 이벤트를 넌시그널 상태로 변환
    HANDLE hEvent            // 이벤트 핸들
);

 

WaitForSingleObject() 함수 : 단일 개체 대기하기

DWORD WaitForSingleObject(
    HANDLE hHandle,                   // 대기할 개체의 핸들
    DWORD dwMilliseconds           // 대기 시간, INFINITE는 무한정 대기
);

 

WaitForMultipleObjects() 함수 : 복수 객체 대기하기

DWORD WaitForMultipleObjects(
    DWORD          nCount,             // 대기할 개체의 개수
    const HANDLE  *lpHandles,        // 기다릴 개체들의 핸들
    BOOL              bWaitall,           // 대기할 개체가 모두 기다려야 하는지 여부
                                               // TRUE : 모든 개체가 시그널 상태가 되기를 대기
                                               // FALSE : 1개의 객체라도 시그널 상태가 되기를 대기
    DWORD           dwMilliseconds  // 대기 시간
);

 

이벤트 이용하기

HANDLE hEvent;

int max;

void ThreadProc(void *arg)

{

    HDC hdc;

    int i;

    int *pX = (int *)arg;

    srand((unsigned)time(0));

    hdc = GetDC(hwnd);

    SelectObject(hdc, CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256) ) );

    for(i = 0; i <= 10; i++)

    {

        int num;

        WaitForSingleObject(hEvent, INFINITE);  // 첫 번째 매개변수에 주어진 이벤트 개체 값이 시그널 상태이면 진행하고
        // 넌 시그널 상태이면 두 번째 매개변수에 주어진 시간 동안 대기한다. 만약 여러 개의 스레드가 동시에 대기 중이면
        // 이 중 하나만 대기에서 풀리고 나머지는 계속 대기하에 된다.

        num = rand()%500;

        if (num > max)

        {

            Sleep(3000);

            max = num;

            Rectangle(hdc, *pX, 0, *pX+20, num);

        }

        SetEvent(hEvent);

    }

    ReleaseDC(hwnd, hdc);

    return;

}

 

#define THREAD_NUM 10

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)

{

    static HANDLE hThread[THREAD_NUM];

    static int xPos[THREAD_NUM];

    int i;

 

    switch (iMsg)

    { 

    case WM_CREATE:

        for (i = 0; i < THREAD_NUM; i++)

            xPos[i] = i*100;

        max = 0;

        break;

    case WM_LBUTTONDOWN:

        hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);

        for (i=0; i<THREAD_NUM; i++)

        {

            hThread[i] = (HANDLE)_beginthreadex( NULL, 0, (unsigned int(__stdcall *)(void *))ThreadProc,

                (void *)&xPos[i], 0, NULL );

            Sleep(2000);

        }

        WaitForMultipleObjects(THREAD_NUM, hThread, TRUE, INFINITE);
        // 두번째 매개변수로 주어진 객체가 모두 시그널 상태인지, 즉 종료되었는지 검사, 시그널 상태가 이나면 대기하는데
        // 세번재 매개변수가 TRUE이면 모든 개체가 시그널 상태가 될때까지 기다리고 FALSE이면 개체하나가 시그널 상태로
        // 변갈 때까지만 기다린다.

        CloseHandle(hEvent);

        break;

    case WM_DESTROY:

        for (i = 0; i < THREAD_NUM; i++)

            CloseHandle(hThread[i]);

        PostQuitMessage(0);

        return 0;

    }

    return DefWindowProc(hwnd, iMsg, wParam, lParam);

}

실행 결과]

 

'프로그램언어 > C++' 카테고리의 다른 글

c++ 표준 라이브러리 array  (0) 2022.07.06
윈도우 프로그램기초예제  (0) 2021.06.08
윈도우 소켓2  (0) 2021.01.13
윈도우 소켓1  (0) 2021.01.12
파일 입출력2  (0) 2021.01.11