
테스트 코드
LOOP : 인큐 및 디큐 횟수
THREAD_NUM : 스레드 갯수
ThreadProc : LOOP횟수만큼 인큐 -> 디큐 반복

LogAnalyzer 프로젝트 코드
1. 2번 CAS 실패시의 지역 tail의 meta값을 ENQ 혹은 DEQ하는 코드에서 건드리는 로그의 갯수를 전부 센다.
2. 위에서 센 갯수만큼 메모리 로그 구조체를 동적할당한 배열을 만들고 값을 복사한다.
3. 2번 CAS 실패시의 지역 metaTail 값을 DEQ에서 더미노드로서 FREE 한 인덱스를 찾는다.
로그 상황 1.


LogAnalyzer에서 분석
96447 인덱스에 2번 CAS 실패 로그 잇음.
pTemp배열의 47번 인덱스의 로그에 FREE로그가 있음.

1번 CAS에서 실제주소 2132c2f9310 지역 metaTail 2082132c2f9310의 next가 null이라서 성공함

같은 스레드가 곧바로 2번 CAS를 시도햇으나 실제주소 2132c2f9310는 같으나 실제 metaTail의 값 actualMetaTail_이 4b02132cf9310으로 같아서 CAS가 실패함.
그 이전의 로그기록에서 아래와 같이 같은 meta주소 2082132c2f9310을 해제햇음을 알수있다.

2번 케이스

인큐 - 디큐 갯수를 30개로 늘리고 스레드를 4개로 늘림.

실제 tail주소 : 2ab0c7616a0 지역 metaTail : 4982ab0c7616a0
그순간의 실제 metaTail_값 :5b0xabc0c75e30

마찬가지로 이전에 지역 metaTail : 4982ab0c7616a0를 FREE 함
1번 CAS를 성공햇다는것은 next가 null이라는것.
next가 null이되는것은 ENQ에서 오브젝트풀에서 노드를 할당받을 때 뿐이다.
첫번째 케이스는 바라보던 지역 tail이 재활용된후에 해당 노드를 인큐하려는 스레드가 1,2번 CAS를성공해서 실제 tail이 되엇고 이때 2번 CAS가 성공한것.
두번쨰 케이스는 바라보던 지역 tail이 재활용된후에 해당 노드를 인큐하려는 스레드가 2번 CAS를 성공하기 전에 1번 CAS 성공후 2번 CAS 를 실패하는것으로 결국 둘다 원인은 같다.
수정된 코드
결국 노드 재활용 문제로 인하여 1번 CAS 성공 -> 2번 CAS 실패가 가능하다.
하지만 이전의 코드는 1번CAS가 성공해야 2번을 수행하기 때문에 이리된다면 2번 실패시 아무도 tail을 옮기지 못하고 1번 CAS를 무한하게 실패하게 된다. 이를 해결하기 위하여

인큐에서는 지역 tail의 next가 null이 아닌경우 2번 CAS를 시도하고 다시 루프 맨처음으로 가서 지역 metaTail을 얻는다.
이때문에 ENQ에서 2번CAS 실패하고 그냥 나가도 됨.

마찬가지로 DEQ에서도 head의 next가 잇는데 metaHead == metaTail 이라면 tail을 옮길수 잇는상황이라면 2번 CAS를 시도해서 tail을 옮기고 다시 루프 맨앞에서 head를 얻어온다
'포폴' 카테고리의 다른 글
| 락프리큐 초기 로깅 - 코드 및 클래스 설명 (0) | 2024.11.09 |
|---|---|
| 락프리큐에 TlsPool 붙이기 - 문제 해결 (0) | 2024.10.18 |
| 락프리큐에 TlsPool 붙이기 - 코드설명 밑 문제제기 (0) | 2024.10.18 |