전에 한번 남들은 lock-free 어케 구현하고 있나 좀 나은 방법 있나 이래 저래 검색해봤더니...
아 글쎄 JAVA로 CAS 기반의 lock-free 구현을 하면서 ABA 드립을 치더라고?
도데체 JAVA로 왜 그런 시간낭비짓을 하는거임?
애초에 lock-free 는 임계영역 진입한 thread가 context-switching 당했을 때 대기중인 쓰레드의 대기시간이 길어지거나 스핀락이 스파이크 발생시키는 문제땜에 하는건데... 인터프리트어에서 왜 그런걸 신경쓰나? 그냥 임계영역만 좀 줄여도 될텐데...
그나마 c++ 로 CAS 기반 lock-free 구현해도 솔까말 critical section 건 것보다 더 느림.
그런데도 c++에서 성능 향상 봤다고 하는 새퀴들 보면 죄다 auto-lock class 쓰고 있더만?
로컬변수 생성자에서 락걸고 소멸자에서 락 풀고 ㅋㅋㅋ 미친 ㅋㅋㅋㅋ 도데체 그 미친짓 누가 시작했는지 쩝 ㅋ
예전에 하이텔 시절에도 누가 그짓 하면 편하다고 지껄이다 캐까였는데... 어째 10년이 지난 지금도 그 지랄들인지 ㅉ
MS 에서 구현해놓은 InterlockedPopEntrySList 도 디버그 걸고 디스어셈 들어가보면
7C932A8C push ebx
7C932A8D push ebp
7C932A8E mov ebp,ecx
7C932A90 mov edx,dword ptr [ebp+4]
7C932A93 mov eax,dword ptr [ebp]
7C932A96 or eax,eax
7C932A98 je 7C932AA6
7C932A9A lea ecx,[edx-1]
7C932A9D mov ebx,dword ptr [eax]
7C932A9F lock cmpxchg8b qword ptr [ebp]
7C932AA4 jne 7C932A96
7C932AA6 pop ebp
7C932AA7 pop ebx
7C932AA8 ret
이래놨는데.. 시발 루프 돌며 cas로 timestamp 써가며 주구장창 lock을 거니 저게 critical section보다 나은 퍼포먼스를 가질 턱볼리가 있나...
이건 뭐 pause 대신 lock# 유발하는 스핀락이니 대략...
뭐 그나마 옛날엔 저게 거의 표준적인 방법론이니까 대강 쓸 사람만 알아서 쓰라고 저따구로 구현해놨겠지 ㅋ
lock-free 제대로 구현하려면 CAS 가 아니라 put:get 을 n:1 로 만들고 put 이 tail 에 lock xchg 하던가, put:get 이 n:n이라면 2의 n승 크기의 queue 에 대한 index 를 lock xadd 하고 and mask 먹이는게.. 내 경험상으론 유일한 해법이더만.
그 짓 못하는 상황에선 그냥 context switching이 임계영역에서 안일어나길 빌면서 임계영역 최소화하고 critical section 쓰는게 낫더라고.
그나마 c++ 같은 바이너리 세계에서나 쓸모가 있지... 도데체 인터프리트어에선 왜 그런 짓을 하는건지...
인터프리트어가 정말로 그 자체로 돌아간다고 믿는건가...
그런게 정말로 JAVA 같은 인터프리트어에서 효과가 있긴 있는거임?
자바는 관심 없어서 할 말이 없는데, C++의 RAII가 왜 까일만 한 건지 한 수 가르쳐주십사 합니다. 궁금함.
몬 소린지 모르겠다 으아아아앙
나도 자바 별로 안 좋아하긴 하지만 개인적으로 자바가 아직도 \"이런 식으로\" 폄하당할 언어는 아니라고 보는데.
근데 동시성(concurrency) 프로그래밍은 내 전문이 아니라서 뭐라 까질 못하겠다. 나는 AtomicInteger.compareAndSet()은 실제로 CAS 연산을 하는 걸로 알고 있는데
요즘 jvm들은 다 JIT 컴파일링 하지 않냐?
그리고 lock-free 까는건 이해 못하겠다. cmpxchg 루프가 있긴 해도 대부분의 경우엔 성공하기 때문에 스핀락만큼 비효율적인건 아니고, lock# 쓰는 명령이 있긴 하지만 그건 critical section도 마찬가지. 거기다 critical section은 thread를 블럭까지 시키잖아.
RAII가 왜 까이는건지는 좀 알고 싶다
kukyakya // auto-lock class 가 왜 까이냐고? 병렬처리의 기본은 임계영역 최소화임. 근데 생성자에서 락을 걸면 물론 오류의 가능성은 줄겠다만... 문제는 임계영역이 너무 커진다는 문제가 있잖아. 동기화할 이유가 없는 다른 개체의 생성자 코드까지도 임계영역에 들어가버리니...
글구 대부분의 경우 성공하는걸로 치면... 굳이 CAS기반의 lock-free 를 쓸 필요 없음. lock-free 보다 critical section 이 훨 코드가 짧고 빠르니까. 문제는 반복횟수가 조또 많은 경우 그 문제가 되는 일부가 재현될 가능성이 높아지기 때문이지. 루프를 도는 횟수가 문제가 아니라 루프 내에서 lock#을 건다는 사실이 중요함. 한마디로 CAS 기반으로 lock-free 구현하면 아무리 퍼포먼스 측정해봐도 배보다 배꼽이 더 커져버림. 단지 critical-section 처럼 스파이크가 발생하지 않을 뿐.