반응형

 

이 글을 먼저 참고한 이후 보시면 됩니다

https://3dmpengines.tistory.com/2237

 

MemoryPool 2 (포인터와 인덱스 값으로 ABA 문제 해결방안 128bit)

interlockedCompareExchange128 의 동작은 아래 글을 참고 https://3dmpengines.tistory.com/2236 InterlockedCompareExchange128 vs InterlockedCompareExchange64 주요 차이점 리턴 값이 다르다 128 비트를 사..

3dmpengines.tistory.com

 

 

위 글하고 같은건데 이것은 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 바이트 정렬을 맞춰 준 다음

포인터 연산을 가능하게 해주면 됩니다

 

 

반응형

+ Recent posts