<aside> 🔒

직접 만든 락프리 자료구조(큐·스택·프리리스트)를 리눅스로 옮긴 기록이다. 이 자료구조는 Win32 Interlocked* 위에서 설계·검증된 것이라, 옮기려면 원자연산부터 다시 짜야 할 것처럼 보였다.

결과는 자료구조 코드 무변경이다. #include 한 줄과 어댑터 헤더 하나로 끝났고, 이 문서는 그게 어떻게 가능했는지와 그 과정에서 딱 하나 실측이 필요했던 지점을 다룬다.

</aside>

<aside> 📌

범위 — g++ 13.3 / x86-64 / Ubuntu 24.04(WSL2) 기준. 코드는 형제 저장소 LockFree_Test/LockFree/.

자료구조 자체의 설계는 여기서 다루지 않는다 — 그건 LockFree 자료구조 계열에 있다. 여기는 이식만 본다.

전체 요약은 1. 왜 옮겼나 · 결과.

</aside>


1. 한눈에 — 무엇을 고쳤나

파일 변경
InternalFreeList.h #include <windows.h>#include "LockFreeCompat.h"1줄
LockFreeQueue.h · LockFreeStack.h · ExternalTlsFreeList.h 없음. 셋 다 InternalFreeList.h를 타고 들어온다
LockFreeCompat.h 신설 — 어댑터 함수 17개, 타입 별칭 8개, 컴파일러 지시자 4개

호출부는 InterlockedCompareExchange128·InterlockedIncrement64 같은 이름을 18곳에서 부른다. 그 18곳을 고치는 대신, 같은 이름·같은 시그니처의 함수를 리눅스용으로 하나씩 만들어 이름이 그대로 통하게 했다.

<aside> 🔑

이렇게 한 이유는 편해서가 아니다. 원본과의 diff가 작아야 이식 중에 생긴 오류를 눈으로 잡을 수 있기 때문이다.

자료구조를 손대면서 옮겼다면, 나중에 문제가 났을 때 "원래 그랬나, 옮기다 깨졌나"를 가릴 수가 없다. 지금은 자료구조 쪽 diff가 한 줄이라 의심할 곳이 어댑터뿐이다.

</aside>

2. 어댑터가 덮은 것

갈래 개수 Windows → 리눅스
원자연산 5 Interlocked*__sync / __atomic (3장에서 자세히)
힙 API 5 HeapCreate·HeapAlloc·HeapFree·HeapDestroy·HeapSetInformationmalloc / free
정렬 할당 2 _aligned_malloc / _aligned_freeposix_memalign / free
스레드 지역 저장소 4 TlsAlloc·TlsFree·TlsGetValue·TlsSetValuepthread_key_*
스레드 양보 1 SwitchToThreadsched_yield
타입 별칭 8 INT64·LONG64·SHORT·PVOID·UINT_PTR·HANDLE·ULONG·DWORD
컴파일러 지시자 4 __forceinline·__declspec·__fastfail·YieldProcessor

대부분은 이름만 바꿔 끼우면 되는 것들이다. 함정이 셋 있었고, 그중 하나는 실측이 필요했다.

3. 16바이트 CAS — __atomic은 함수 호출을 낸다 ★

이 문서에서 유일하게 길게 쓸 대목이다.

왜 16바이트인가

이 자료구조는 ABA 문제를 포인터와 카운터를 붙여 한 번에 교환하는 방식으로 푼다. 포인터 8바이트 + 카운터 8바이트 = 16바이트를 원자적으로 바꿔야 하고, x86-64에서 그 명령이 cmpxchg16b다. Windows에서는 InterlockedCompareExchange128이 그 명령으로 내려갔다.

GCC에는 이걸 쓰는 방법이 둘이다.

당연히 앞의 것을 골랐다. 그리고 그게 틀렸다.

실측 — 같은 플래그로 컴파일한 두 함수