시즌 2: 멀티쓰레드 프로그래밍이 왜이리 힘드나요?

21,536 views

Published on

Lock-free 멀티쓰레드 프로그래밍 기법과 Transactional Memory를 실제 사용예제를 통해 설명하고, 성능을 보여줌.

Published in: Technology
11 Comments
98 Likes
Statistics
Notes
  • @kernel0

    정확이 이야기한다면 말씀하신대로 volatile은 compiler문제만 해결하지 CPU의 ordering문제는 해결하지 못합니다. 슬라이드에서는 모든 문제를 한번에 해결하지 않고 compiler부터 차근 차근 해결하는 것을 보여주려고 일부러 volatile이야기를 할 때는 ordering문제를 언급하지 않고, 나중에 ordering 문제를 언급한 것입니다.

    C++11의 atomic을 통한 해결이 정석이긴 하지만 volatile보다 성능이 떨어지는 문제가 있습니다. 다음 발표에서는 volatile과 atomic의 비교가 추가되어야 할 것 같습니다. strong과 weak ordering의 비교는 시간 관계상 생략했습니다. ^^

    좋은 비평 감사드립니다.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • 안녕하세요. volatile 관련해서는 시즌1에서 visual studio 에서 volatile 을 썼더니 문제가 없었다고 하셨는데요. 좀 더 자세한 설명이 슬라이드에 있었으면 오해가 없었을 것 같습니다.
    @Dongseong Hwang 님이 volatile 을 쓰는게 말도 안된다고 한 의미는 volatile keyword 가 표준C++ 스펙에서는 visibility 를 보장하고 있지 않아서 라고 생각합니다.
    volatile은 compiler reordering을 막지 processor reordering을 막지는 못하잖아요.
    물론 시즌1 실험해보신 것 대로 VisualStudio의 x86/x64 빌드 옵션에서는 보장이 될 겁니다. volatile이 좋아서가 아니라 x86/x64가 strong memory model 이기 때문이겠지요.

    (Windows의 ARM 포팅으로 최근에 몇몇내용이 추가되었더군요.) MSDN의 volatile keyword 페이지(http://msdn.microsoft.com/en-us/library/12a04hfd.aspx)를 보시면
    'microsoft specific' 한 환경에서 volatile은 교수님이 원한 결과를 보장하는 내용이 나옵니다. 그와 함께 ARM 에서는 지원하지 않는다.
    쓰레드간 통신에는 volatile 을 사용하는 것을 권장하지 않는다.라며 슥 발을 빼려고 하지요.(vs2005 때 msdn 에서는 지들이 우린 volatile 로 DCL문제를 해결했다!며 자랑했었는데 말이죠 :) )

    이런 오해를 낳을 만한 내용보다는 건설적으로(?) C++11에서 제공한 라이브러리로 문제를 해결한 것을 제시한다거나, volatile은 한정적으로 써야 한다는 얘기와 함께
    weak vs strong memory model 에 대한 설명을 해주셨으면 더더욱 유익한 강연이 되었을 것 같습니다.

    시즌2까지 잘 보았습니다. 시즌3도 기대합니다!
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • @jyhpsycho
    답변을 드리자면.

    1. 시즌1의 예제는 진정한 Lock-free가 아니지 않는가?
    local_sum을 사용한 '정답'프로그램을 말씀하시는 것 같은데, Lock-free가 아닙니다.
    Lock-free알고리즘에 대해 이야기하기 전에 소개해 드린 간단한 프로그램일 따름입니다. ^^
    추가로 말씀드리면 그 프로그램의 목적은 아무리 옵티마이즈 해도 Lock을 모두 없애기는 힘들다는 것을 보여주는 것도 있습니다.

    2. 시즌2의 lock-free도 while loop를 도니까 lock과 마찬가지 아닌가?
    lock-free도 while loop를 허용합니다. 단지, 한가지 조건이 더 붙을 따름입니다.
    그 조건은 '전체 쓰레드를 보았을 때 상수(constant)시간 동안 반드시 하나 이상의 메소드(while loop)가 종료하여야 한다.'는 것이죠.
    Lock의 경우 위의 조건을 만족하지 않습니다. 따라서 서로 배치되는 주장이 아닙니다.
    lock-free보다 더 엄격한(좋은)알고리즘인 wait-free의 경우도 while loop를 허용합니다. 단 조건이 '상수 번 루프를 돌면 무조건 종료해야만 한다'로 바뀝니다.

    Lock-free와 Locking알고리즘의 차이는 좀 미묘하고 헷갈리기 쉽습니다.


    3. thread safe에 관하여 증명된 것은 'Compare-and-Set이 없으면 3개 이상 쓰레드에서의 lock-free 알고리즘의 작성이 불가능 하다.'입니다. Lock만 사용해도 얼마든지 thread safe만들 수 있고, Lock없어도 lock-free가 아닌 thread safe프로그램을 얼마든지 만들 수 있습니다. 단지 성능상의 문제게 있을 따릅입니다.

    4. 어차피 성공할 때 까지 while loop를 도는데 차라리 시스템에서 제공하는 Lock을 사용하는 것이 쉽고 빠르지 않는가?
    그렇지 않습니다. 두가지 이유가 있는데요.
    첫째는 Lock을 사용할 경우 싱글쓰레드에서만 실행되서 성능의 병목이 되는 Lock으로 커버되는 구간이 상당히 커집니다. Lock-free는 atomic operation만 병목이고 나머지는 병렬적으로 돌아가죠, 그렇기 때문에 Amdahl의 법칙에 의해 lock-free알고리즘의 병렬성이 훨씬 좋아져서 성능이 올라갑니다. Lock의 구현 오버헤드는 덤이구요.
    둘째는 Priority Inversion과 Convoying때문입니다. RW-Lock을 쓰거나 lock-free가 아닌 busy-waiting으로 구현했을 때 큰 문제가 됩니다.

    5. Profiling이 먼저 필요하다.
    이것은 당연한 이야기 입니다. lock-free알고리즘도 profiling을 해서 계속 성능개선을 하여야 합니다.
    제 경험상 많은 경우 profiling을 했을 때 lock-free알고리즘의 성능이 뛰어났습니다.

    6. 독선적이다.
    네, 말투가 독선적이었습니다. 하지만 위의 주장은 저만의 주장이 아니라 교과서에도 나오는, 논문으로 다 증명이 된 이야기입니다. 본인들의 짧은 경험으로 옛날에 증명이 된 이야기를 부정하면 열받습니다.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • 내용 잘 봤습니다. 전 특별히 관련 전공자는 아닙니다만 한 가지 의문이 드는 게, 진정한 lock-free라는 게 과연 가능한가 하는 점입니다. 시즌 1의 예제... 그 '정답'에서도 Thread-local로 계산을 완료하고 마지막에는 lock을 사용하게 되어 있고, 지금 시즌 2의 lock-free라는 데서도 실상은 atomic 연산이 정확하게 완료될 때까지 while loop를 돕니다. 그 자체로 이미 lock의 기능을 하고 있다고 생각하는데 아닌가요? 그런 종류의 개념이 아예 없이 thread safe한 프로그램을 짜는 게 불가능하다고 수학적으로 증명됐다는 소리까지 여기 자료들에서 본 것 같은데 그 두 주장은 서로 배치되는 거 아닙니까?
    물론 실패시 커널 함수를 호출한다는 운영체제 제공 lock 메커니즘 대신 프로그램 자체에서 조건을 검사하는 것이 반응속도가 더 빠를 수는 있습니다. 대신 while 루프를 도는 만큼의 CPU cycle을 낭비한다는 건 어떤 방식을 쓰더라도 똑같습니다. 거기에 응용에 따라서는 차라리 운영체제 제공 lock을 쓰는 게 더 쉽고 빠를 수도 있겠죠. 이건 제가 프로그램을 취미로 짜며 발로 만들어서 그런지는 모르겠지만, 실제로 경험한 일입니다. 이 부분에 대해서는 다른 분 말마따나 Profiling이 먼저 필요하다고 봅니다. 자기가 무조건 옳다고 믿으며 자기와 다른 주장을 하는 사람을 무시하고 겸손해지라고 질책하기 전에 말입니다.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • @dongseonghwang
    1. Volatile을 쓰지 말라니요? 어이가 없네요. 시즌 1을 보세요. -_-
    2. 게임은 굉장히 성능이 중요한 분야입니다. 회사의 존망이 달려 있으니 락프리를 합니다.
    3. 락으로 동기화 하면 어떤 일이 벌어지는지 시즌 1을 보세요.
    4. 소개해 주신 책은 제가 2009년 부터 계속 강의하고 있는 책이고, 재미있게 잘 읽고, 내용을 잘 써먹고 있습니다. 시즌 1을 보세요.
    5. 하아... 슬라이드에 검증된 알고리즘 쓰라고 제가 말했는데요? 29페이지 보세요.
    6. 고성능 멀티쓰레드 프로그래밍에 대한 경험이 없으신것 같은데 좀 겸손해 지세요.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
21,536
On SlideShare
0
From Embeds
0
Number of Embeds
656
Actions
Shares
0
Downloads
216
Comments
11
Likes
98
Embeds 0
No embeds

No notes for slide

시즌 2: 멀티쓰레드 프로그래밍이 왜이리 힘드나요?

  1. 1. 시즌 2 : 멀티쓰레드 프로그래밍이 왜이리 힘드나요? (Lock-free에서Transactional Memory까지) 정내훈 한국산업기술대학교 게임공학과
  2. 2. 발표자 소개  KAIST 전산과 박사 − 전공 : 멀티프로세서 CPU용 일관성 유지 HW  NCSoft 근무 − Alterlife 프로그램 팀장 − Project M(현 Blade & Soul) 프로그램 팀장 − CTO 직속 게임기술연구팀  현 : 한국산업기술대학교 게임공학과 부교수 − 학부 강의 : 게임서버프로그래밍 − 대학원 강의 : 멀티코어프로그래밍, 심화 게임서버 프로그래밍 2-2
  3. 3. 참고  삼성 첨단기술연수소에서 강의한 내용 반영 − 40시간 강의 (실습 포함) => 뒷부분 만 발췌  대학원 4주 강의 분량의 압축 2-3
  4. 4. 2-4 목차  도입 : 그래도 멀티쓰레드 프로그램을 하시려구요?  대책  성능  미래 또는 현실
  5. 5. 도입  제가 하는 발표 들어본 적이 있으신 분?  멀티쓰레드 프로그래밍 경험 있으신 분?  Lock-free 자료 구조가 무엇인지 아시는 분? 2-5 CJ E&M, NDC, KGC2012, 삼성, JCE
  6. 6. 도입  멀티쓰레드 프로그래밍의 위험성 − “자꾸 죽는데 이유를 모르겠어요”  자매품 : “이상한 값이 나오는데 이유를 모르겠어요” − “더 느려져요” 2-6 [미] MuliThreadProgramming [mʌ́ltiθred-|proʊgrӕmɪŋ] : 1. 흑마술, 마공 2. 위력이 강대하나 다루기 어려워 잘 쓰이지 않는 기술
  7. 7. 도입  멀티쓰레드 프로그래밍의 어려움 (한페이지 요약) − Data Race : 2를 5천만번 더했는데 1억이 안 나오는 경우.  Lock을 사용해 해결 − 컴파일러 : 변수를 참조했는데, 컴파일러가 무시  volatile 키워드로 해결 − CPU : 프로그램을 자기 마음대로 변조  asm mfence; 명령으로 해결 − Cache : -1을 썼는데 65535가 써짐  포인터 주소 확인하기. − 성능 : 싱글 쓰레드 버전보다 더 느림  Lock 쓰지 말자. 2-7 ABA 문제는?
  8. 8. 목차  도입  대책 : Lock-free 프로그래밍이 도대체 뭐야?  성능  미래 또는 현실 2-8
  9. 9. 대책  현실의 멀티쓰레드 프로그램은? − 여러 쓰레드가 동시에 멀티 코어에서 실행된다. − 쓰레드간의 데이터 공유 및 동기화는 안전한 Lock-free 자료구조를 통해서 이루어진다. − 언리얼 3 : 디스플레이 리스트 Queue − 각종 게임 서버 : Job Queue외 다수 2-9
  10. 10. 대책  Lock-free 알고리즘을 사용하여야 한다.  사용하지 않으면 − 병렬성 감소 − Priority Inversion − Convoying − /* 성능이 떨어지고 랙이 발생한다 */ − /* 작년에 보여드렸어요~~ */ 10
  11. 11. 대책  Lock-free 알고리즘이란? − 여러 개의 쓰레드에서 동시에 호출했을 때에도 정해진 단위 시간마다 적어도 한 개의 호출이 완료되는 알고리즘. 11 ??????
  12. 12. 대책  Lock-free 알고리즘이란? − 자료구조 및 그것에 대한 접근 방법  예) QUEUE : enqueue, dequeue  예) STACK : push, pop  예) 이진 트리 : insert, delete, search 12
  13. 13. 대책  Lock-free 알고리즘이란? − 멀티쓰레드에서 동시에 호출해도 정확한 결과를 만들어 주는 알고리즘  STL 탈락. − Non-Blocking 알고리즘  다른 쓰레드가 어떤 상태에 있건 상관없이 호출이 완료된다. − 호출이 다른 쓰레드와 충돌하였을 경우 적어도 하나의 승자가 있어서, 승자는 delay없이 완료 된다. 13
  14. 14. 대책  (보너스) − Wait-free 알고리즘은?  호출이 다른 쓰레드와 충돌해도 모두 delay없이 완료 된다.  추가 상식 − LOCK을 사용하지 않는다고 lock-free 알고리즘이 아니다!!! − LOCK을 사용하면 무조건 lock-free알고리즘이 아니다. 14
  15. 15. 대책  알고리즘의 분류 15 알고리즘 싱글쓰레드 멀티쓰레드 Blocking Non-blocking Lock-free Wait-free …. ….
  16. 16. 대책  예) Blocking 알고리즘 16 EnterCriticalSection(&mylock); sum = sum + 2; LeaveCriticalSection(&mylock); EnterCriticalSection(&mylock); q.push(35); LeaveCriticalSection(&mylock); while (dataReady == false); asm mfence; temp = g_data;
  17. 17. 대책  왜 Blocking인가? − dataReady에 true가 들어가지 않으면 이 알고리즘은 무한 대기, 즉 다른 쓰레드에서 무언가 해주기를 기다린다. − 여러 가지 이유로 dataReady에 true가 들어오는 것이 지연될 수 있다.  Schedule out, 다른 쓰레드 때문에 대기 17 while (dataReady == false); temp = g_data;
  18. 18. 대책  Non-blocking은? 18 InterlockedExchangeAdd(&sum, 2); q.push(35); LF_QUEUE::push(int x) { Node *e = New_Node(x); while (true) { Node *last = tail; Node *next = last->next; if (last != tail) continue; if (NULL == next) { if (CAS(&(last->next), NULL, e)) { CAS(&tail, last, e); return; } } else CAS(&tail, last, next); } }
  19. 19. 대책  Non-blocking은? 19 if (dataReady == false) return false; asm mfence; temp = g_data;
  20. 20. 대책  CAS? − CAS가 없이는 대부분의 non-blocking 알고리즘들을 구현할 수 없다.  Queue, Stack, List… − CAS를 사용하면 모든 싱글쓰레드 알고리즘 들을 Lock-free 알고리즘으로 변환할 수 있다!!! − Lock-free 알고리즘의 핵심 20
  21. 21. 대책  정리 − Lock-free 알고리즘을 써야한다.  성능때문이다.  CAS가 꼴 필요하다.  CAS − CAS(&A, old, new); − 의미 : A의 값이 old면 new로 바꾸고 true를 리턴 − 다른 버전의 의미 : A메모리를 다른 쓰레드가 먼저 업데이트 해서 false가 나왔다. 모든 것을 포기하라. 21
  22. 22. 대책  Lock-free 알고리즘은 어떻게 구현되는가?  알고리즘의 동작이란? − 기존의 자료구조의 구성을 다른 구성으로 변경하거나 자료구조에서 정보를 얻어내는 행위 22 3 Head Tail 1 9X 3 Head Tail 1 9X push(35); 35
  23. 23. 대책  Lock-free 알고리즘은 어떻게 구현되는가? 23 자료구조의 변경을 시도한다. 성공했는가? 완료 yes no (time machine) 시도 전으로 되돌아간다.. ??? ???
  24. 24. 대책  Lock-free 알고리즘은 어떻게 구현되는가?  앞의 알고리즘이 불가능 하므로 24 자료구조의 변경을 시도한다. but, 다른 쓰레드가 먼저 변경했으면 시도 취소. 성공했는가? 완료 yes no 현재의 자료구조를 파악한다.
  25. 25. 대책 25 자료구조의 변경을 시도한다. but, 다른 쓰레드가 먼저 변경했으면 시도 취소. CAS while (true) { int old_sum = sum; if (true == CAS(&sum, old_sum, old_sum+2)) break; } 결과물 EnterCriticalSection(&mylock); sum = sum + 2; LeaveCriticalSection(&mylock);
  26. 26. 대책 26 자료구조의 변경을 시도한다. but, 다른 쓰레드가 먼저 변경했으면 시도 취소. CAS LF_QUEUE::push(int x) { Node *e = New_Node(x); while (true) { Node *last = tail; Node *next = last->next; if (last != tail) continue; if (NULL != next) continue; if (CAS(&(last->next), NULL, e, &tail, last, e)) return; } } QUEUE::push(int x) { Node *e = new Node(x); tail->next = e; tail = e; }
  27. 27. 대책 27 현실 LF_QUEUE::push(int x) { Node *e = New_Node(x); while (true) { Node *last = tail; Node *next = last->next; if (last != tail) continue; if (NULL != next) continue; if (CAS(&(last->next), NULL, e, &tail, last, e)) return; } } LF_QUEUE::push(int x) { Node *e = New_Node(x); while (true) { Node *last = tail; Node *next = last->next; if (last != tail) continue; if (NULL == next) { if (CAS(&(last->next), NULL, e)) { CAS(&tail, last, e); return; } } else CAS(&tail, last, next); } } 하지만 2개의 변수에 동시에 CAS를 적용할 수 는 없다!
  28. 28. 대책  … − 알고리즘이 많이 복잡하다. − 그래서 작성시 실수하기가 쉽다. − 실수를 적발하기가 어렵다.  하루에 한두 번 서버 크래시  가끔 가다가 아이템 증발 − 제대로 동작하는 것이 증명된 알고리즘을 사용해야 한다. 28
  29. 29. 대책  결론 − 믿을 수 있는 non-blocking container들을 사용하라.  Intel TBB, Visual Studio PPL − 자신을 포함한 출처가 의심스러운 알고리즘은 정확성을 증명하고 사용하라.  정확성이 증명된 논문에 있는 알고리즘은 OK. 29
  30. 30. 목차  도입  대책  성능 : 데스크탑에서 동접 1만 서버를 만들어 보자.  미래 또는 현실 30
  31. 31. 성능  간단한 MMORPG 서버를 만들어 보자 − 1000x1000 world − 60x60 sector − 시야 30 − 1000마리의 몬스터  플레이어 접근 시 자동 이동 및 공격 − 이동/공격/채팅 가능 − Windows에서 IOCP로 구현
  32. 32. 성능  성능 향상을 위해 − 시야 처리시 검색 성능을 위해 월드를 sector로 분할하여 주위 sector만 검색  병렬 검색을 위해 tbb::concurrent_hash_map사용 − 몬스터 AI 처리를 모든 쓰레드에서 균등하게 나누어 처리하기 위해 timer와 event시스템 사용  timer queue 병렬 등록을 위해 tbb::concurrent_priority_queue를 사용 − 객체 id의 재사용을 막고 메모리 재사용을 위해 객체 id와 객체 배열의 인덱스를 쌍으로 관리  <id, index>의 병렬 검색을 위해 tbb::concurrent_hash_map 사용
  33. 33. 성능  성능 측정용 DummyClient − 서버에게 부하를 걸 수 있도록 여러 명의 Player를 에뮬레이션 해주는 프로그램 − 사람이 플레이 하는 것과 비슷하게 Player를 주기적으로 랜덤한 방향으로 이동 시킴 − 한명의 유저당 하나의 소켓 연결을 하므로 서버에서는 일반 클라이언트 접속과 DummyClient접속이 서로 차이가 없음 − 훌륭한 UNIT TESTER − /* 이것도 IOCP로 구현, Direct3D로 유저 분포 실시간 디스플레이 */
  34. 34. 성능 34
  35. 35. 성능  실행 결과 − Intel i7 920 2.67GHz 머신에서 실행  동접 8000 정도까지 − Lock-free 자료구조로 최적화 하기 전에는 동접 3000 정도가 한계.
  36. 36. 목차  도입  대책  성능  미래 또는 현실 : Transactionl 메모리, 그리고… 36
  37. 37. 현실  멀티쓰레드 프로그래밍 도우미 (1/2) − Intel TBB  좋은 성능, 유용한 라이브러리  Concurrent 자료 구조 − Visual Studio PPL  Intel TBB와 유사 − OpenMP  컴파일러 레벨에서 병렬 프로그램 API를 제공  성능과 골치 아픈 문제들은 그대로
  38. 38. 현실  멀티쓰레드 프로그래밍 도우미 (2/2) − CUDA, OpenCL, DirectCompute  멀티코어 활용이 아니라 GPU활용  렌더링 하느라 바쁜 GPU를 건드리지 마세요.  I/O처리가 불가능해서 서버 Core Logic에는 적용 불가능
  39. 39. 현실  암담한 현실 − Blocking Algorithm  성능 저하, priority inversion, convoying  Deadlock! − Non-blocking Algorithm  높은 난이도로 인한 생산성 저하  어쩌라고???? Transactional Memory!
  40. 40. 현실  Transactional Memory? 2-40 Tim Sweeny at GameTech2010
  41. 41. 현실  Transactional Memory는 − 아까 본 바로 그 그림을 그대로 구현한 것… 자료구조의 변경을 시도한다. 성공했는가? 완료 yes no (time machine) 시도 전으로 되돌아간다..
  42. 42. 현실  Transactional Memory가 좋은 이유? − 생산성! − 싱글쓰레드 프로그램을 그대로 쓸 수 있음  하지만 멀티쓰레드에서 Lock-free하게 실행됨. LF_QUEUE::push(int x) { atomic { Node *e = new Node(x); tail->next = e; tail = e; } } LF_QUEUE::push(int x) { Node *e = New_Node(x); while (true) { Node *last = tail; Node *next = last->next; if (last != tail) continue; if (NULL == next) { if (CAS(&(last->next), NULL, e)) { CAS(&tail, last, e); return; } } else CAS(&tail, last, next); } } Lock-free 구현 Transactionl Memory 구현
  43. 43. 현실  Transactional Memory의 사용법 − 다른 쓰레드와 충돌이 일어날 수 있는 구간을 transaction으로 선언한다. 끝, 이게 전부
  44. 44. 현실  어떻게 가능한가??? 1. transaction 구간에서 읽고 쓴 메모리를 다른 쓰레드에서 접근했는지 검사한다.  write는 실제 메모리에 쓰지 않고 잠시 대기 2. 다른쓰레드에서의 접근이 있었으면 모든 업데이트를 무효화 한 후 다시 시도. 3. 다른쓰레드에서의 접근이 없었다면 transaction 구간에서의 update를 실제 메모리에 update
  45. 45. 현실  그게 가능하다고??  어떻게 − Software적으로 메모리 업데이트를 관리하면 됨 (STM: Software Transactional Memory) − 또는, 하드웨어가 알아서 해줌 (HTM: Hardware Transactional Memory) 2-45
  46. 46. 현실  Transactional Memory  장점 − 높은 생산성  기존의 프로그램을 그대로 사용 가능  단점 − STM : 오버헤드로 인한 속도 저하 − HTM : HW 필요.  한계점 − 쓰레드가 너무 많을 경우 잦은 충돌로 인한 성능향상의 한계 2-46
  47. 47. 현실  Transactional Memory  지금까지는 꿈속의 개념이고 8 Core이상에서 STM의 성능을 기대하는 정도였으나.  Intel에서 일을 저지름. 2-47 2013년 6월 HASWELL말매 Haswell은 HTM을 지원.
  48. 48. 현실  Intel Haswell 2-48
  49. 49. 트랜잭션 메모리의 구현  Haswell의 HTM − 복수개의 메모리에 대한 Transaction을 허용한다.  Cache Line 8개 까지 − CPU에서 transaction 실패시의 복구를 제공한다.  메모리와 레지스터의 변경을 모두 Roll-back한다. − Visual Studio 2012, update 2에서 지원 2-49
  50. 50. 트랜잭션 메모리의 구현  하드웨어 트랜잭션 메모리 예제 2-50 DWORD WINAPI ThreadFunc(LPVOID lpVoid) { for (int i=0;i<500000000 / num_thread;++i) { while (_xbegin() != _XBEGIN_STARTED) _xabort(0); sum += 2; _xend(); } return 0; }
  51. 51. 트랜잭션 메모리의 구현  하드웨어 트랜잭션 메모리 예제 (Set의 Add) 2-51 bool Add(int key) { NODE *pred, *curr; NODE *node = new NODE(key); while(true) { pred = &head; curr = pred->next; while (curr->key < key) { pred = curr; curr = curr->next; } if (_XBEGIN_STARTED != my_xbegin()) { _xabort(0); continue; } if (!validate(pred, curr)) { _xabort(0); continue; } if (key == curr->key) { _xend(); delete node; return false; } else { node->next = curr; pred->next = node; _xend(); return true; } } } HTM Lock-Free
  52. 52. 트랜잭션 메모리의 구현  Haswell HTM의 한계 − 모든 알고리즘에 적용 불가능  HW 용량 한계 => 알고리즘의맞춤형 수정 필요.  Nested Transaction불가능 − 오버헤드  모든 레지스터 내용 저장 및 Roll-back 2-52 그리고…
  53. 53. 트랜잭션 메모리의 구현 2-53 휴… 밥줄 끊길뻔…
  54. 54. 미래  HTM이 업그레이드 되어서 보급되면 끝인가? − 쓰레드가 많아 질 수록 충돌확률이 올라가 TM의 성능이 떨어진다. − 64Core 정도가 한계일 것이라고 예측하고 있다. (2010 GameTech, Tim Sweeny)
  55. 55. 미래  왜 쓰레드사이에 충돌이 생기는가? − C 스타일 언어를 사용하기 때문이다.  공유 메모리  side effect  해결책은? C 비슷한 언어를 버린다. − 대신 함수형 언어 사용  공유 메모리 없고 side effect없음
  56. 56. 새로운 언어  주목받고 있는 언어 − 하스켈  순수 함수형 언어로 1990년에 개발  개념은 뛰어나나 난이도로 인해 많이 사용되지 못하고 있음. − Earlang  에릭슨에서 전자 계산기용으로 1982년에 개발  Scalable한 서버 시스템에 자주 사용되고 있음 2010GDC
  57. 57. 새로운 언어  함수형 언어의 문제 − 익히기 어렵다.
  58. 58. 정리  Lock-free 알고리즘이 무엇인가? − 어떤 조건을 만족해야 하는가? − 어떻게 구현되는가? − 왜 어려운가? − 하지만 왜 써야만 하는가.  멀티쓰레드 프로그래밍의 미래. − Transactional Memory  진격의 INTEL − 새로운 언어의 필요 2-58
  59. 59. NEXT  다음 주제(내년???) − Lock-free search : SKIP-LIST − ABA Problem, aka 효율적인 reference counting − 고성능 MMO서버를 위한 non- blocking자료구조의 활용 2-59
  60. 60. Q&A  연락처 − nhjung@kpu.ac.kr − 발표자료 : ftp://210.93.61.41 id:ndc21 passwd: <바람의나라> − Slideshare에 올릴 예정.  참고자료 − Herlihy, Shavit, “The Art of Multiprocesor Programming, Revised”, Morgan Kaufman, 2012 2-60

×