티스토리 뷰

190702-3
 
교육을 받으면서 노트필기 했던 내용을 날것 그대로 업로드합니다.

#include <stdio.h>
#include <windows.h>
void Sleep()
{
    for(int i = 0 ; i < 100000000 ; ++i)
        ;
}
DWORD __stdcall ThreadFunc(LPVOID pParam)
{
    int* pnum = (int*)pParam;
    //int num = *pnum;
 
    printf("ThreadFunc Param : %d 생성\n", *pnum);
    for(int i = 0 ; i < 10 ; ++i)
    {
        printf("ThreadFunc[%d] : %d\n", *pnum, i);
        Sleep();
    }
 
    return 0;
}
 
void main()
{
    DWORD threadID;
    HANDLE hThread[2];
    
 
    hThread[0] = CreateThread(0,0,ThreadFunc, (LPVOID)new int(1), 0, &threadID);// new로 동적할당한 주소를 전달 공유변수 문제를 해결한다.
    hThread[1] = CreateThread(0,0,ThreadFunc, (LPVOID)new int(2), 0, &threadID);
 
 
    //쓰레드 종료 대기(모든 쓰레드의 신호상태를 기다림)
    WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
 
    CloseHandle(hThread[0]);
    CloseHandle(hThread[1]);
}
 
 
int GetCountNum()
{
    __declspec(thread) static int count = 0; //정적 TLS(컴파일 시점에 결정한다.) ●(TLS메모리에 생성한다.)
 
    return count++;
}
 
슬롯 : 어떤 공간에 동일한 방식으로 넘버링이 되어있는 것이다.
#include <stdio.h>
#include <windows.h>
DWORD tlsIndex;
DWORD __stdcall ThreadFunc(LPVOID pParam)
{
    //__declspec(thread) static int num = (int)pParam; //정적 TLS X
    TlsSetValue(tlsIndex, (LPVOID)pParam);//tlsIndex 슬롯에 번호 저장
    //● 해당 인덱스에 LPVOID에 들어온 값을 넣는다. (슬롯에 넣는다.)
 
    printf("ThreadFunc Param : %d 생성\n", (int)TlsGetValue(tlsIndex));
    //● TlsGetValue 호출 시점에 자기 자신 메모리의 인덱스 값을 읽는다.
    for(int i = 0 ; i < 10 ; ++i)
    {
        printf("ThreadFunc[%d] : %d\n",(int)TlsGetValue(tlsIndex), i);
        Sleep(500);
    }
 
    return 0;
}
 
void main()
{
    DWORD threadID;
    HANDLE hThread[2];
 
    tlsIndex= TlsAlloc(); //TLS 슬롯 할당, 동적 TLS //● tls인덱스를 받는다.
    printf("TLS 슬롯 %d index 생성\n", tlsIndex);
    hThread[0] = CreateThread(0,0,ThreadFunc, (LPVOID)1, 0, &threadID);
    hThread[1] = CreateThread(0,0,ThreadFunc, (LPVOID)2, 0, &threadID);
 
 
    //쓰레드 종료 대기(모든 쓰레드의 신호상태를 기다림)
    WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
 
    TlsFree(tlsIndex); //TLS 슬롯 제거
    CloseHandle(hThread[0]);
    CloseHandle(hThread[1]);
}
 
쓰레드의 정지/재개
#include <stdio.h>
#include <windows.h>
 
DWORD __stdcall ThreadFunc(LPVOID pParam)
{
    printf("ThreadFunc Param : %d 생성\n", GetCurrentThreadId());
    for(int i = 0 ; i < 100 ; ++i)
    {
        printf("ThreadFunc[%d] : %d\n",GetCurrentThreadId(), i);
        Sleep(500);
    }
 
    return 0;
}
void main()
{
    DWORD threadID;
    HANDLE hThread;
 
    hThread = CreateThread(0,0,ThreadFunc, (LPVOID)0, CREATE_SUSPENDED/*멈춰논다(블로킹상태)*/, &threadID);
 
    printf("쓰레드를 동작하려면 엔터키를 누르세요.\n");
    getchar();
    ResumeThread(hThread); //● 쓰레드를 동작시킨다.
 
    printf("쓰레드를 정지하려면 엔터키를 누르세요.\n");
    getchar();
    SuspendThread(hThread); //● 정지시킨다.
    printf("쓰레드를 다시 동작하려면 엔터키를 누르세요.\n");
    getchar();
    ResumeThread(hThread); //● 다시 동작 시킨다.
 
    //쓰레드 종료 대기(모든 쓰레드의 신호상태를 기다림)
    WaitForSingleObject(hThread, INFINITE);
 
    CloseHandle(hThread);
}
 
● 쓰레드의 원자적 연산
  • HW에서는 마이크로연산(CPU에서 처리되는 단위연산)
  • SW에서의 원자적 연산 : 다른 쓰레드나 프로세스에 영향받지 않고 실행할 수 있는 단위.
    ex) n의 결과치를 1증가시키는 연산이 있을 때.
    이 여산은 os따라서 명령어가 다르게 나누어진다. 하지만 크게 3가지 연산으로 본다.
    Read n -> INC n -> Write n (3가지 연산이 결합이 된다.)
  • 원자적인 연산 : 어떤 연산이 수행되는 동안 다른 연산에 의해 방해가되면 안된다. (명령 한줄두줄이 아님)
 
● 쓰레드 선점당할시 발생하는 문제
#include <stdio.h>
#include <windows.h>
 
int val=0;
 
DWORD __stdcall ThreadFunc(LPVOID pParam)
{
    printf("ThreadFunc Param : %d 생성\n", GetCurrentThreadId());
    for(int i = 0 ; i < 1000000 ; ++i)
    {// 여기서 뺃기면 끝!!!
        ++val;
    }
 
    return 0;
}
 
void main()
{
    DWORD threadID;
    HANDLE hThread[2];
 
    hThread[0] = CreateThread(0,0,ThreadFunc, (LPVOID)0, 0, &threadID);
    hThread[1] = CreateThread(0,0,ThreadFunc, (LPVOID)0, 0, &threadID);
 
 
    //쓰레드 종료 대기(모든 쓰레드의 신호상태를 기다림)
    WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
    printf("val : %d\n", val);
 
    CloseHandle(hThread);
}
 
 
#include <stdio.h>
#include <windows.h>
 
int val=0;//공유변수
 
DWORD __stdcall ThreadFunc(LPVOID pParam)
{
    printf("ThreadFunc Param : %d 생성\n", GetCurrentThreadId());
    for(int i = 0 ; i < 1000000 ; ++i)
    {
        //++val;
        InterlockedIncrement((long*)&val);
    }
 
    return 0;
}
 
void main()
{
    DWORD threadID;
    HANDLE hThread[2];
 
    hThread[0] = CreateThread(0,0,ThreadFunc, (LPVOID)0, 0, &threadID);
    hThread[1] = CreateThread(0,0,ThreadFunc, (LPVOID)0, 0, &threadID);
 
 
    //쓰레드 종료 대기(모든 쓰레드의 신호상태를 기다림)
    WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
    printf("val : %d\n", val);
 
    CloseHandle(hThread[0]);
    CloseHandle(hThread[1]);
}
 
싱크 두 가지가 있다.
  1. 데이터가 분산되어있을 때 그 데이터를 동일하게 만들어 내는 것.
  2. 순서제어. 두개가있는데 어떤 공유자원을 누가 먼저쓸지. 순서제어를 하는 것.
 
#include <stdio.h>
#include <windows.h>
#include <process.h> // _beginthreadex 헤더
 
//C 런타임 라이브러리의 static 변수를 TLS로 할당한다.
unsigned int __stdcall ThreadFunc(LPVOID pParam)
{
    printf("ThreadFunc Param : %s\n", pParam);
    for(int i = 0 ; i < 10 ; ++i)
    {
        printf("ThreadFunc : %d\n", i);
        Sleep(500);
    }
 
    _endthreadex(0); //종료
 
    return 0;
} //반환 형식 unsigned int
 
void main()
{
    unsigned threadID; //(int) 생략가능
    HANDLE hThread;
 
    hThread = (HANDLE)_beginthreadex(
        0,
        0,
        ThreadFunc,
        "Hello!",
        0,
        &threadID // unsigned int*
        ); //반환 형식 uintptr_t
 
    WaitForSingleObject(hThread, INFINITE);
 
    CloseHandle(hThread);
}
  • CreateThread() : API함수
  • _beginthreadex() : C런타임 라이브러리 함수를 감안한 함수다. 
 
C런타임함수(실행시간에사용)
  • scanf,gets : 입력 버퍼를 쓴다.
쓰레드1,쓰레드2 동시에 입력을 받고싶을 경우.
 
댓글
댓글쓰기 폼