본문 바로가기

포폴

락프리큐 초기 로깅 - 코드 및 클래스 설명

클래스 설명

*meta가 붙은 변수들은 ABA문제를 막기위해 실제 변수에 상위 17비트값을 추가함

nodePool_ : 락프리 스택으로 만들어진 오브젝트 풀

metaTail_ : tail의 meta주소

metaHead_ : head의 meta주소

metaCnt_ : 상위 17비트에 들어갈 값을 인터락으로 만들때 사용함

num_ : 큐가 보관중인 요소의 갯수

 

ENQ : 1번 CAS 성공후 2번 CAS 성공시 break;

DEQ : 비어있다면 나가고 비어있지 않으면 진입.

head의 next가 null이면 continue

metaHead_ == metaHead(지역변수) 이면 head의 next로 CAS

성공시 더미노드를 Free한다. 미리 복사해두엇던 값을 반환한다.

 

왜 ret으로 미리 복사해두엇나?

CAS 성공 후 ret에다가 data를 복사한다면 다른 스레드가 복사전에 반환하고 재활용되서 재활용 된 값이 반환될수도잇음.

 

메모리 로그 구조체

EVENT : 로그 찍는 상황을 분류한것

1. ENQ_FIRST_CAS_SUCCESS : 인큐 하려는 노드의 next == null일때 추가하고자 하는 노드의 meta주소를 next에 넣고자 한 CAS가 성공시 찍는 로그

2. WRITE_MEMORY_LOG_SECOND_CAS_SUCCESS : 1번 CAS가 성공하고 2번 CAS가 성공햇을때 찍은 로그

3. WRITE_MEMORY_LOG_SECOND_CAS_FAILED : 1번 CAS가 성공하고 2번 CAS가 실패시 찍는 로그

4. WRITE_MEMORY_LOG_DEQ_FREE : Dequeue에서 더미노드를 락프리 오브젝트풀에 반환시 찍는 로그

 

멤버변수 설명 

1. localMetaTail_ : Enqeueue 혹은 Dequeue에서 큐의 멤버변수 metaTail_값을 저장하는 지역변수

2. pLocalRealTail_ : 위의 localMetaTail_에서 상위 17비트를 제거한 실제주소

3. actualMetaTail_ : 2번 CAS에서는 지역변수 metaTail과 실제 metaTail_을 비교하는데 이때 CAS가 반환하는 metaTail_의 초깃값 따라서 위의 2,3을 제외하고는 쓰이지 않는다.

4. metaNext_ : 1번 CAS가 실패햇을때 찍으려고 준비한것인데 사실상 핵심은 2번 CAS가 성공한것이라 1번 실패는 적지않으므로 사실상 의미가 없어짐.

5. newMetaTail_ : 1번 CAS 성공시 next에 2번 CAS성공시 metaTail_이 해당값으로 변하게 된다.

6. metaFreeDummy_ :  DEQ에서 반환된 더미 노드의 상위 17비트가 조작된 meta주소

7. pRealFreeDummy_ : 위 metaFreeDummy_의 실제주소

 

메모리 로그 찍기 설명

ULONGLONG 카운터를 늘려가면서 배열상의 인덱스를 구해가며 메모리 로그를 찍는다.

아래 WRITE_MEMORY_LOG_SECOND_CAS_FAILED 함수는 로그를 찍은 인덱스를 반환하는데 이는 

해당 함수가 찍은 로그가 논리적으로 확인해야하는 로그의 끝이기 때문에 빠르게 해당 위치를 찾기위함임

 

MemLogWriteToFile : 2번 CAS 실패시 로그 배열 , 인덱스를 만들기 위한 로그 카운터, 마지막 로그 인덱스값을 파일에 저장한다. 로그 카운터를 저장하는 이유는 배열에 원형방식으로 로그를 적기때문에 배열끝에 도달해서 다시적엇는지를 확인하기 위함임.

 

MemLogRead : 로그를 분석하는 프로젝트에서만 사용하는 함수임. ARRAY_SIZE 크기의 배열과 Counter, 마지막 인덱스를 받을 변수의 주소를 넣으면 담아준다.