목록분류 전체보기 (35)
AlphaMOT
[Lock Free 자료구조 구현 Intro]락-프리 자료구조의 성능이 다른 동기화 객체 더불어 활용되는 자료구조보다 더 우월한가 아닌가는 프로그램의 경향성을 파악해야 하며, 성능 분석을 통해 결정할 수 있는 선택 사항이다.락-프리 자료구조 구현의 이유는 설계와 구현의 과정에서 발생하는 동기화 이슈들을 맞닥뜨리며, 여러 디버깅 기법을 통해 해결해 나가고자 하는 것에 의의를 두었다.락-프리 구조를 어떻게 만들어야 thread-safe 할 수 있는지 파악. 이러한 경험을 바탕으로 일반적인 멀티-스레딩 프로그래밍 작성 시 임계 영역 설정과 동기화 객체 활용에 수월하기를 기대한다.구현 및 테스트 과정에서 발생되는 동기화 오류 등을 맞닥뜨리고, 메모리 분석, 로그 기록 등 다양한 디버깅 기법을 적용하여 문제를 해..
[SRWLock(Slim Reader Writer Lock)]EnterCriticalSection 어셈블리어에서 LockCount의 특정 비트를 Interlocked 방식으로 제어하여 다른 스레드들의 동시 진입을 제어하였다. SRWLock에서도 이러한 방식을 사용하지만, Reader / Writer 비트로 나누어 체크한다.공유 자원을 읽기만 하는 스레드의 경우 동시 접근해도 무방하지만, 공유 자원을 수정하려는 쓰기 스레드가 있는 경우 배타적 접근이 필요하기에 두 경우를 나눈 것이라 볼 수 있다.SRWLock에서도 내부적으로 어느 정도의 스핀-락이 돌고, NtWaitForAlertByThread를 호출하여 블록되는 방식이다. [SRWLock 특징]단일 SRW 락은 어느 모드에서든 획득할 수 있다. rea..
CriticalSection, SRWLock 동기화 객체의 Lock, Unlock 함수는 WaitOnAddress, WakeByAddress 기반으로 구현되었다. WaitOnAddress에서 임계 영역 진입 여부(Address 참조 값 확인)는 유저 모드로 동작한다. 만약 블록 상태 전환 필요 시 커널 모드로의 전환이 발생한다. 락의 반환은 WakeByAddress로 수행한다.동기화 객체를 통해 락을 선점할 시 곧바로 WaitOnAddress를 호출하는 것은 아니다. 'spin-count' 멤버를 통해 어느 정도의 스핀 루프를 돌며 몇 번의 타임 슬라이스 내 락 점유를 시도하고, 실패하면 WaitOnAddress 호출을 통해 블록 상태로 전환한다. [CriticalSection]Critical Secti..
[WaitOnAddress]BOOL WaitOnAddress ( [in] volatile VOID* Address, [in] PVOID CompareAddress, [in] SIZE_T AddressSize, [in, opt] DWORD dwMilliseconds);Address: Address 주소 내 데이터를 CompareAddress 주소 내 데이터와 비교. 값이 일치하지 않다면 대기 상태로 전환되지 않고 즉시 반환되며, 같은 경우 대기 상태로 전환된다.AddressSize: 비교 대상 크기 (1/2/4/8)dwMilliSeconds: 대기 시간WaitOnAddress에서 Address의 값을 확인하는 것은 진입 시점 때 만이다. 비교되는 값과 비교하여 같은지, 다른지 여부로 반환/블록 여부를 판단..
[두 가지 관점에서의 스레드 동기화]실행 순서 동기화스레드의 실행 순서를 정의하고, 이 순서에 반드시 따르도록 하는 동기화이다.주로 이벤트(Event) 동기화 객체를 통해 이러한 실행 순서 동기화 로직을 구현한다.메모리 접근 동기화스레드 간 공유되는 데이터 영역이나 힙 영역 중 한 순간에 하나의 스레드만이 접근해야 하는 메모리 영역이 존재한다. 이러한 메모리 접근에 있어 동시 접근을 막는 것 또한 스레드 동기화에 해당한다.실행 순서 동기화와는 달리 여러 스레드가 특정 순서로 접근하는 것으로 제한하지 않는다. 단지 동시 접근 문제점 만을 막는 동기화 방식이다.주로 CriticalSection, Mutex, Semaphore 동기화 객체, Interlocked 계열 함수를 통해 메모리 접근 동기화 로직을 구..
[InterlockedExchange를 활용한 스핀-락]SpinLock(int* lockFlag) { while(true) { before = InterlockedExchange(&lockFlag, 1); // before == 0: 현재 스레드가 0 -> 1 변경, break (락 획득) // before == 1: 현재 스레드가 변경 수행 실패, spin wait... if(before == 0) break; }}SpintUnlock(int* lockFlag) { // 플래그 복구, 캐시 라인 내 쓰기 원자성을 보장하기에 단순 대입 lockFlag = 0;} [스핀-락 활용]CriticalSection, Semap..
[CPU-level 원자적 수행]Interlocked 계열의 함수는 연산은 최소 단위 오퍼레이션에 맞춘 하나의 명령어로 컴파일되어 연산의 원자성을 보장하는 함수이다. 운영체제 차원이 아닌 CPU 차원의 원자적 연산을 유도하는 것이다. 최소 단위 오퍼레이션에 맞춘다는 것은 해당 오퍼레이션을 수행하는 시점 만큼은 인터럽트가 발생하지 않아 제어의 흐름이 핸들러로 넘어가지 않게 되어 데이터 무결성을 지켜주게 하는 것이다. Interlocked 계열 함수에 앞서 기본적으로 CPU 레벨에서 보장하는 원자적 수행에 대해 알아보겠다.프로세서는 아래와 같은 기본적인 메모리 연산에 대해 언제나 원자적 처리를 보장한다.Read/Write a ByteRead/Write a Word(16bit) aligned on a 16-b..
[세션의 제거와 연결 종료(closesocket)]비동기 I/O 완료 통지를 처리하는 IOCP 작업자 스레드 설계에서는 '세션의 제거'와 '연결 종료(closesocket)'는 별도임을 인지해야 했다. 기존 동기 I/O 수행 서버 설계와는 다르다. 일반적으로 동기 I/O 방식에서는 recv 함수에서 EOF(0)가 반환되면, 곧바로 세션 제거와 closesocket 함수를 통해 소켓 자원을 정리하고 연결 종료를 진행하였다. IOCP 기반 비동기 처리의 코드 구조는 아래와 같다.{ GetQueuedCompletionStatus(..); if(송수신 결과 == EOF) { // 세션 제거? 소켓 정리? } if(수신 완료) { // 수신 처리.. }..