운영체제 & 병렬처리/Multithread
MemoryPool 3 (MS-lock-free stack, ABA 문제 해결방안 128bit)
3DMP
2022. 10. 13. 05:32
이 글을 먼저 참고한 이후 보시면 됩니다
https://3dmpengines.tistory.com/2237
위 글하고 같은건데 이것은 MS 에서 제공하는 내장 함수를 사용하는 안전한 방식 입니다
(이전 코드에는 약간의 테스트코드에서 하자가 있음) => 기본 제공 하는 MS 방식이 검증된것으로 안전한 방식이기도..
제공되는 SLIST_HEADER 는 아래와 같습니다 (이전 코드와 같은 걸 알 수 있습니다)
typedef union DECLSPEC_ALIGN(16) _SLIST_HEADER {
struct { // original struct
ULONGLONG Alignment;
ULONGLONG Region;
} DUMMYSTRUCTNAME;
struct { // x64 16-byte header
ULONGLONG Depth:16;
ULONGLONG Sequence:48;
ULONGLONG Reserved:4;
ULONGLONG NextEntry:60; // last 4 bits are always 0's
} HeaderX64;
} SLIST_HEADER, *PSLIST_HEADER;
SLIST_ENTRY 또한 다음 노드만 가리키는 형태입니다
typedef struct DECLSPEC_ALIGN(16) _SLIST_ENTRY {
struct _SLIST_ENTRY *Next;
} SLIST_ENTRY, *PSLIST_ENTRY;
아래는 MS 것을 사용한 테스크 코드입니다
헤더(SLIST_HEADER)가 있고 그 이후로 SLIST_ENTRY 를 추가하거나 삭제 할수 있습니다, 멀티스레드 환경에서, 스택처럼
lock-free stack 은 다음 처럼 사용하면 됩니다
DECLSPEC_ALIGN(16)
class Data // : public SListEntry
{
public:
SLIST_ENTRY _entry;
int64 _rand = rand() % 1000;
};
SLIST_HEADER* GHeader;
int main()
{
GHeader = new SLIST_HEADER();
ASSERT_CRASH(((uint64)GHeader % 16) == 0);
//헤드 초기화
InitializeSListHead(GHeader);
for (int32 i = 0; i < 3; i++)
{
GThreadManager->Launch([]()
{
while (true)
{
Data* data = new Data();
ASSERT_CRASH(((uint64)data % 16) == 0);
//헤드에 다음 노드 추가
::InterlockedPushEntrySList(GHeader, (SLIST_ENTRY*)data);
this_thread::sleep_for(10ms);
}
});
}
for (int32 i = 0; i < 2; i++)
{
GThreadManager->Launch([]()
{
while (true)
{
Data* pop = nullptr;
pop = (Data*)::InterlockedPopEntrySList(GHeader);
if (pop)
{
cout << pop->_rand << endl;
delete pop;
}
else
{
cout << "NONE" << endl;
}
}
});
}
GThreadManager->Join();
}
추가적으로
DECLSPEC_ALIGN(16)
class Data // : public SLIST_ENTRY
{
public:
SLIST_ENTRY _entry;
int64 _rand = rand() % 1000;
}
Data 부분은 SLIST_ENTRY 를 상속 받거나 멤버변수에 첫번째로 넣어 16 바이트 정렬을 맞춰 준 다음
포인터 연산을 가능하게 해주면 됩니다
반응형