게임서버 공부_socket_멀티 스레드
1. 스레드
1.1 스레드 생성
CreateThread(6);
# include <processthreadsapi.h>
// 성공 : 스레드 핸들 반환 -> 다른 API 스레드 정보 접근용.
// 실패 : NULL, 자세한건 GetLastError
HANDLE CreateThread(
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes, // NULL
[in] SIZE_T dwStackSize, // 스택 사이즈, default 사용은 0
[in] LPTHREAD_START_ROUTINE lpStartAddress, // 스레드 함수
[in, optional] __drv_aliasesMem LPVOID lpParameter, // 스레드 함수 전달 인자
[in] DWORD dwCreationFlags, // 스레드 생성 제어. 0 - 바로시작/ CREATE_SUSPENDED - ResumeThread() 대기
[out, optional] LPDWORD lpThreadId // 스레드 ID저장됨. 필요없을수도.
);
- lpStartAddress가 접근 불가하거나 이상해도 해당 함수는 핸들을 반환. 그리고 스레드 동작 후 예외가 발생한 다음 스레드가 종료된다.
1.2 스레드 함수
ThreadProc(1)
// 아래의 형태로 사용자가 구현.
// 선언 및 정의 ThreadProc는 예약 키워드이지만 바꿔도 됨.
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
// 스레드 기능 구현
}
1.3 스레드 종료
ExitThread(1)
# include <processthreadsapi.h>
void ExitThread(
[in] DWORD dwExitCode
);
스래드 내부에서 스레드를 종료.
TerminateThread(2)
# include <processthreadsapi.h>
// 성공 : TRUE / 실패 : FALSE, 자세한건 GetLastError
BOOL TerminateThread(
[in, out] HANDLE hThread, // 스레드 핸들. ID아님.
[in] DWORD dwExitCode
);
스레드 외부에서 핸들을 통해 스레드를 종료시키는 함수.
1.4 스레드 우선순위 레벨
SetThreadPriority(2)
#difine THREAD_PRIORITY_IDLE -15
#difine THREAD_PRIORITY_LOWEST -2
#difine THREAD_PRIORITY_BELOW_NORMAL -1
#difine THREAD_PRIORITY_NORMAL 0
#difine THREAD_PRIORITY_ABOVE_NORMAL 1
#difine THREAD_PRIORITY_HIGHEST 2
#difine THREAD_PRIORITY_TIME_CRITICAL 15
# include <processthreadsapi.h>
// 성공 : TRUE / 실패 : FALSE, GetLastError
BOOL SetThreadPriority(
[in] HANDLE hThread,
[in] int nPriority
);
GetThreadPriority(1)
// 스레드 우선순위 반환.
int GetThreadPriority(
[in] HANDLE hThread
);
우선순위 레벨을 반환함.
1.5 스레드 종료 대기 -> 동기화 객체 state확인.
WaitForSingleObject(2)
#include <synchapi.h>
// WAIT_ABANDONED : 포기된 동기화객체. 해당 객체 반환불가 상태면 OS가 강제로 신호상태로 만들고, WAIT_ABANDONED를 반환(ex - 스레드가 동기화 객체 선점 후 Terminated되는 경우).
// WAIT_OBJECT_0 : 신호상태가 되어 선점 받음
// WAIT_TIMEOUT : 시간초과
// WAIT_FAILED : 실패. 자세한건 GetLastError
DWORD WaitForSingleObject(
[in] HANDLE hHandle,
[in] DWORD dwMilliseconds // 최대 대기 시간.
);
특정 오브젝트(이 성우 스레드)가 종료될때까지 기다리는 함수.
WaitForSingleObjects(4)
#include <synchapi.h>
// WAIT_ABANDONED : 포기된 동기화객체. 해당 객체 반환불가 상태면 OS가 강제로 신호상태로 만들고, WAIT_ABANDONED를 반환(ex - 스레드가 동기화 객체 선점 후 Terminated되는 경우). https://codemuri.tistory.com/160
// WAIT_OBJECT_0 : 신호상태가 되어 선점 받음
// WAIT_TIMEOUT : 시간초과
// WAIT_FAILED : 실패. 자세한건 GetLastError
DWORD WaitForMultipleObjects(
[in] DWORD nCount, // 동기화 객체 개수
[in] const HANDLE *lpHandles, // 동기화 객체 배열
[in] BOOL bWaitAll, // SIGNED 전부 : TRUE / SIGNED 하나라도: FALSE
[in] DWORD dwMilliseconds // 대기 시간
);
여러개의 오브젝트(이 경우 스레드)들이 종료될때까지 기다리는 함수.
1.6 스레드 중지 및 재실행
SuspendThread(1)
#include <processthreadsapi.h>
// 성공 : suspend(중지) count
// 실패 : (DWORD) -1 -> DWORD형의 -1...
DWORD SuspendThread(
[in] HANDLE hThread
);
특정 스레드 일시 정지(block? sleep?)
ResumeThread(1)
#include <processthreadsapi.h>
// 성공 : suspend(중지) count
// 실패 : (DWORD) -1 -> DWORD형의 -1...
DWORD ResumeThread(
[in] HANDLE hThread
);
일시 정지된 특정 스레드를 재시작.
sleep(1)
#include <synchapi.h>
void Sleep(
[in] DWORD dwMilliseconds
);DLE hThread
해당 스레드를 입력된 시간(msec 단위)정지. 그 후 재시작.
2. 스레드 동기화
2.1 임계 영역
초기화 - InitializeCriticalSection(1)
#include <synchapi.h>
CRITICAL_SECTION CS
// 윈도우 비스타 이후부터는 STATUS_NO_MEMORY 예외 없이 무조건 성공.
void InitializeCriticalSection(
[out] LPCRITICAL_SECTION lpCriticalSection
);
반환값이 없으므로, 끝나고 errno확인할 것.
접근 - EnterCriticalSection(1)
#include <synchapi.h>
CRITICAL_SECTION CS
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-entercriticalsection#return-value
void EnterCriticalSection(
[in, out] LPCRITICAL_SECTION lpCriticalSection
);
탈출 - LeaveCriticalSection(1)
#include <synchapi.h>
CRITICAL_SECTION CS
void LeaveCriticalSection(
[in, out] LPCRITICAL_SECTION lpCriticalSection
);
삭제 - DeleteCriticalSection(1)
#include <synchapi.h>
CRITICAL_SECTION CS
void DeleteCriticalSection(
[in, out] LPCRITICAL_SECTION lpCriticalSection
);
2.2 이벤트
생성 - CreateEventW(4)
#include <synchapi.h>
// 성공 : 핸들
// 이미 있음 : ERROR_ALREADY_EXISTS, 자세한 정보는 GetLastError
// 실패 : NULL, 자세한 정보는 GetLastError
HANDLE CreateEventW(
[in, optional] LPSECURITY_ATTRIBUTES lpEventAttributes, // null
[in] BOOL bManualReset, // 수동 TRUE / 자동 FALSE
[in] BOOL bInitialState, // 생성시 신호 상태
[in, optional] LPCWSTR lpName // 이벤트 명.
);
- bManualReset
- 수동리셋 : TRUE - 대기하는 스레드 모두 깨우고 신호상태 유지.
- 자동리셋 : FALSE - 대기하는 스레드 하나만 깨우고 비신호 상태 변환.
- lpName : 이름이 안곂치면 create, 곂치면 open(다른 프로세스에서 쓰고 있는걸 공유하게 됨).
이벤트 대기 : 동기화 객체 state확인 함수들
이벤트 제거시 핸들 제거CloseHandle() 사용. CloseHandle()로 닫는 객체들
닫기 - CloseHandle(1)
#include <handleapi.h>
// 성공 : TRUE / 실패 : FALSE, 자세한 정보는 GetLastError
BOOL CloseHandle(
[in] HANDLE hObject
);
원격(연결된 상대) 주소 정보(IP, PORT)정보 반환.
추가
소켓 구조체에서 address정보를 얻는 함수.
원격 - getpeername(3)
#include <winsock.h>
int getpeername(
[in] SOCKET s,
[out] sockaddr *name,
[in, out] int *namelen
);
원격(연결된 상대) 주소 정보(IP, PORT)정보 반환.
지역 - getsockname(3)
#include <winsock.h>
int getsockname(
[in] SOCKET s,
[out] sockaddr *name,
[in, out] int *namelen
);
지역(호스트 = 나) 주소 정보(IP, PORT)정보 반환.