Windows의 thread 생성 함수
POSIX는 pthread_create, cpp는 thread로 생성
HANDLE WINAPI CreateThread(
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress, // 함수포인터
_In_opt_ __drv_aliasesMem LPVOID lpParameter, // 매개변수
_In_ DWORD dwCreationFlags,
_Out_opt_ LPDWORD lpThreadId // Thread ID
);
typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(
LPVOID lpThreadParameter
);
typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE;
DWORD WINAPI ThreadStartFunction(LPVOID lpThreadParameter)
위 형식의 함수 정의 후 함수포인터로 CreateThread에 넘기면 Thread생성
Return값인 Handle과 반환된 ThreadID를 통해 Thread 제어 가능
이 때 Return된 Handle은 CloseHandle()을 통해 닫아줘야 함
CPP11부터 추가된 Thread는 호환성이 떨어질 수 있다고 함
CPU 스케줄링 기법
대표적으로 Round Robin이 있음
Thread가 CPU를 점유하면 Thread Quantum동안 CPU 점유를 보장
재밌는 점은 Thread에서 유휴시간이 없으면 해당 Thread에서 CPU를 독점하여 다른 작업을 할 수 없다는 이야기가 있음
테스트 결과 맞기도 하고 틀리기도 한 말인듯
DWORD WINAPI Thread1(LPVOID lpThreadParameter)
{
while (1)
{
//Sleep(1);
printf("1");
}
}
DWORD WINAPI Thread2(LPVOID lpThreadParameter)
{
while (1)
{
//Sleep(1);
printf("2");
}
}
int main()
{
//SetProcessAffinityMask(GetCurrentProcess(), 1);
HANDLE handle1 = CreateThread(0, 0, Thread1, 0, 0, 0);
SetThreadAffinityMask(handle1, 1); // Thread의 수행 core를 제한하는 함수
HANDLE handle2 = CreateThread(0, 0, Thread2, 0, 0, 0);
SetThreadAffinityMask(handle2, 1);
while (1)
{
//Sleep(1);
int i = 0;
}
}
위 코드처럼 sleep같은 유휴 시간 없이 각 Thread가 출력을 하는 프로그램을 실행 시
이처럼 단일 Thread의 출력이 꽤 길게 유지되는 것을 확인할 수 있음
Sleep을 풀 경우
느리지만 전반적으로 꽤 균일하게 Thread가 수행되는 것을 확인할 수 있음
찾아보니 Thread의 context switching이 꼭 유휴시간이나 interrupt에서만 발생하는 것은 안닌듯 함
위 자료에 의하면 IO interrupt, Thread API(Sleep, WaitForSingleObject 등) 외에도 메모리에 Memory Page Fault가 발생하거나 해당 Thread의 Time Slice(Thread Quantum)을 다 할 경우 Context switching이 발생한다고 함
다만, 이 경우는 코드상으로는 확인이 어렵고, 실행 시점을 짐작하기도 어렵기 때문에 명시적으로 Sleep같은 함수를 이용하여 Context Switching을 수행하는 것이 균등한 프로그램 수행을 유도할 수 있을 듯
Sleep의 경우 0과 1에 차이가 있다고 함
Sleep(N) : N밀리초만큼 시간 조각을 포기
Sleep(0) : 같은 우선순위의 쓰레드에게 시간 조각을 양도
Sleep(1) : 다른 쓰레드에게 시간 조각을 양도
프로세스의 스레딩과는 다른 개념인 듯 한데 단순히 코어를 늘리지 않아도 실제로 성능 향상이 있는 듯
Multi Thread를 할 경우 메모리 가시성과 메모리 장벽은 중요한 개념
나중에 한번 읽어보면 좋을 듯
TCP의 경우 Sliding Window를 통해서 데이터를 순차적으로 전달하고, Protocol Header에서도 FIN Flag를 통해 모든 데이터의 전송이 완료되었는지 여부를 확인할 수 있음
찾아보니 Socket의 Read Buffer에 저장되는 값은 TCP가 모든 데이터를 전송한 후 완결된 Data가 아닌 TCP Packet이 전송한 데이터 단위로 Read Buffer에 작성이 되는 구조인 듯
이 때문에 Sender에서 보낸 데이터의 크기가 Receiver가 읽고자 하는 Buffer의 크기보다 더 작은 크기의 또는 MTU 1500보다 작은 데이터를 보내더라도 네트워크 환경에 따라 데이터는 분할이 될 수 있고 Receiver는 분할된 데이터를 받을 때마다 recv()함수를 호출할 수 있음