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]);
}
싱크 두 가지가 있다.
-
데이터가 분산되어있을 때 그 데이터를 동일하게 만들어 내는 것.
-
순서제어. 두개가있는데 어떤 공유자원을 누가 먼저쓸지. 순서제어를 하는 것.
#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 동시에 입력을 받고싶을 경우.
'System Programming' 카테고리의 다른 글
[system programming] 핸들, 커널 오브젝트, 프로세스 등 (0) | 2019.07.04 |
---|---|
[system programming] WS_CHILD, SuspendThread, ResumeThread 등 (0) | 2019.07.04 |
[system programming] 커널오브젝트와 핸들, 핸들 테이블, 신호 비신호 상태, 쓰레드 등 (0) | 2019.07.04 |
[system programming] 핸들, 동기, 신호/비신호 (0) | 2019.07.03 |
[system programming] 커널오브젝트, 아스키코드와 유니코드 (0) | 2019.07.03 |