SlideShare a Scribd company logo
C++ Concurrency in Action Study
C++ Korea
C++ Korea
C++ Concurrency in Action
Study C++ Korea 박 동하 (luncliff@gmail.com)
C++ Korea 최 동민 (dongminchoi90@gmail.com)
C++ Concurrency in Action Study
C++ Korea
지난 이야기(4장)
2
• 조건 변수
• future
• promise
• async
• packaged_task
• shared_future
• 시간 측정
• chrono
• Using synchronization of operations to simplify code
• 함수형 프로그래밍
• Communicating Sequential Process
C++ Concurrency in Action Study
C++ Korea
오늘의 내용
C++ Concurrency in Action Study
C++ Korea
Part 1.
메모리 모델 기초
4
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
5
객체지향을 처음 배울 때
Q. 객체란 무엇인지 쓰시오. (1점)
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
6
C++ 의 모든 데이터 : “객체”
• “모든 것은 객체이다.” - by Ruby or SmallTalk
• “객체란 메모리 공간의 한 영역이다.” - by C++ 표준
• 객체란 단지 만들어진 데이터 블록의 상태를 의미.
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
7
객체란 메모리 공간의 한 영역
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
8
우리가 이미 알고 있는 것
다른 스레드가 같은 객체를 접근하면
Data Race
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
9
우리가 이미 알고 있는 것
다른 스레드가 같은 객체를 접근하면
Data Race ?
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
10
객체는 메모리 안의 특정 공간에 저장
• 한 객체는 기본적으로 최소한 하나의 메모리 공간 차지
• 기본형(POD)들은 정확히 하나의 메모리 공간 차지
• 인접해 있거나, 배열의 원소이더라도
• 단, 인접한 비트 필드 (Adjacent bit fields)는
하나의 메모리 블록으로 취급
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
11
#progma pack(4) 일 때
이 구조체의 필드는 메모리에 어떻게 잡힐까요?
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
12
책에 나온 해답
한 메모리 공간에
두 객체
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
13
테스트 환경 : VS2015 Update 1, 32bit App, Debug
실제로 해보니, 다른 메모리 공간에 할당
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
14
합이 32bit 초과.
-> 쪼갠다.
합이 32bit 이하.
-> 합친다.
테스트 환경 : VS2015 Update 1, 32bit App, Debug
같은 메모리 공간에 할당
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
15
같은 메모리 공간에 할당
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
16
이것이 왜 중요한가?
문제 없음
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
17
이것이 왜 중요한가?
Data Race!
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
18
같은 메모리 공간을 접근
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
19
같은 메모리 공간을 접근한 결과
‘인접한 비트 필드’의 경우,
심지어 다른 객체를 참조했음에도 Data Race
Data Race 는 곧 미정의 동작(Undefined Behavior)
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
20
미정의 동작(Undefined Behavior)
• C++의 가장 끔찍한 부분 중 하나
• 한 번 일어나면, 그 어플리케이션은 망한 거나 다름 없음.
• 어떠한 일이라도 일어날 수 있음.
• “제가 알고 있는 미정의 동작 중 하나는
당신의 모니터에 갑자기 불이 붙는 것입니다.”
– Anthony Williams
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
21
동공 지진
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 객체와 메모리 공간
22
하지만 우리는 이 끔찍한 길을 걷기로 다짐했습니다.
• Data Race 가 있는 메모리 공간에 접근 시
원자적 연산을 사용
• Data Race 를 근본적으로 막을 수는 없지만,
프로그램을 정의된 동작으로 되돌릴 수 있다.
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 수정 순서
23
또 하나 알아야 할 개념 : 수정 순서 (Modification Orders)
• 쓰기 순서(write order) 라고도 함
• 한 객체에 대한 모든 쓰기 연산에 순서를 정의한 것
• 오직 한 순간에, 하나의 쓰기만이 허용된다고 가정
• 모든 스레드에서, 이 순서는 일치해야 함.
C++ Concurrency in Action Study
C++ Korea24
수정 순서
write(3)
write(10)
write(-1)
초기값:0
i 의 변천사
0
3
-1
10
메모리 모델 기초 수정 순서
C++ Concurrency in Action Study
C++ Korea25
스레드가 보는 수정 순서
메모리 모델 기초 수정 순서
이 보는 i 의 변천사
0
3
10
가 보는 i 의 변천사
0
3
-1
10
??-65535
C++ Concurrency in Action Study
C++ Korea26
메모리 모델 기초 수정 순서
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 수정 순서
27
우리가 원하는 것
• Data Race 로 인한 미정의 동작을 피하고 싶다.
• 서로 다른 스레드에서 보는 수정 순서를 맞추고 싶다.
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 수정 순서
28
누구의 책임인가?
• 컴파일러, CPU는
기본적으로 멀티 스레드에 대한 책임이 없다.
• 싱글 스레드 단위로 판단
• 우리가 해야 할 일
• 적절한 원자적 연산을 사용해서,
컴파일러에게 수정 순서를 맞추라고 알려주는 것.
• 원자적 연산 사용 시
• 컴파일러는 필요한 동기화를
필요한 위치에 넣을 책임을 지게 된다.
C++ Concurrency in Action Study
C++ Korea
메모리 모델 기초 수정 순서
29
원자적 연산을 쓰면 되는군요!
• 그런데 이게 무엇인지?
• 어떤 연산들이 있는지?
• 어떨 때 써야 하는지?
• 어디에 써야 하는지?
• Part2 에서 알아봅시다.
C++ Concurrency in Action Study
C++ Korea
Part 2.
C++에서의
원자적 연산들과 자료형
30
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
31
1 + 1 = 1?
!!
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
32
원자적 연산이란?
• 더 이상 나눌 수 없는 연산
• 연산이 반만 된 상태를 관측할 수 없음
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
33
비원자적 연산
• ++a;
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
34
비원자적 연산
• ++a 를 두 스레드에서 동시에 실행할 경우
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
35
원자적 연산
• ++a;
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
36
원자적 연산
• InterlockedExchange
InterlockedAdd …
• 이게 C++ 표준 인가요?
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
37
표준 atomic types
• #include<atomic>
• 표준에서는, 오로지 이 타입들의 연산만이 원자적.
• 아니면 lock을 사용해서 “원자적으로 보이게“ 해야 함.
• is_lock_free() 멤버함수를 가짐.
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
38
Lock Free 가 뭔가요?
락으로부터 자유롭나?
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
39
Lock Free(무잠금) 란?
• Lock 없이 연산을 즉시 완료할 수 있으면 Lock Free!
• 뮤텍스나 Critical Section 같은 “Lock” 은 획득하지 못했을 시
스레드의 Sleep을 유발 -> 성능에 치명적
• Lock 은 적을 수록 좋다.
대표 함수 – InterlockedAdd(), InterlockedExchange(),
InterlockedCompareExchange()
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
40
Lock Free 구현
• 하드웨어 지원
• 명령어 존재. 실패할 일 없음.
• 소프트웨어 구현
• 명령어로는 지원할 수 없는 복잡한 알고리즘의 경우 직접 구현 필요
• Compare And Swap(CAS) 로 구현
• PASS. 다음 챕터 분들께 양도합니다.
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
41
atomic<T>::is_lock_free()
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
42
이게 무슨 원리래요
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
43
is_lock_free() 구현
VS2013, 2015에서는
8바이트 이하의 객체면
Lock-Free
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
44
8byte 초과 시
짤없음
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
45
Lock Free 가 아니면?
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
46
8byte 초과 Type
atomic<Type>::store() 내부구현
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
47
8byte 초과 시 Lock
음 스핀락이군요
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
48
8byte 초과 시 Lock?
음 스핀락이군요
잉???
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
49
8byte 초과 시 Lock
• 당황스럽긴 하지만, 정상적인 구현
• “memcpy() 쯤이야 오래 걸려봤자 얼마나 걸린다고..”
• 언젠가는 락을 가져오는데 성공한다.
• atomic<T> 가 지원하는 연산 중 복잡한 로직이 없기 때문에 가능한 구현.
ex : “컨테이너에서 유저를 찾아서 현재 체력이 0 이하면 마을로 귀환“
이런 거 못함.
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
50
다시 본론으로 돌아갑니다.
• atomic<T> 클래스를 보고 있었죠?
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
51
<atomic>
• std::atomic_flag
• 반드시 lock-free
• test_and_set() or clear() 만 가능한 BOOL
• std::atomic<T>
• T 타입에 따라, 다른 연산자 제공
• lock-free가 아닐 수도 있음
• 아무 클래스나 T에 넣을 수는 없음. 제약이 존재.
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
52
<atomic>
• std::atomic_flag
• std::atomic<bool>
• std::atomic<T*>
• std::atomic<int>
• std::atomic<T>
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
53
<atomic>
• std::atomic_flag
• std::atomic<bool>
• std::atomic<T*>
• std::atomic<int>
• std::atomic<T>
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
54
std::atomic_flag
• 반드시 초기화 필요
• ATOMIC_FLAG_INIT
• 파라미터로 memory order 지정.
• clear(std::memory_order_release)
“이 변수를 초기화할 때 release 의미론을 사용하라”
• 디폴트는 std::memory_order_seq_cst
• 가장 강력한 의미론. 선형화
• 조금 있다 자세히
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
55
std::atomic_flag
• bool atomic_flag::test_and_set()
• 변수가 현재 true 이면, 그냥 true를 리턴
• 변수가 현재 false 이면, 값을 true로 바꾸고 이전 값인 false 리턴
• 용례
• Spin Lock
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
56
std::atomic_flag
• 방금 보았던 8byte 초과 atomic<T> 타입의 내부 스핀락
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
57
std::atomic_flag 를 이용한 spinlock mutex 구현
“바쁜 대기라 좋은 선택은 아니지만, 상호 배제를 보장하긴 합니다”
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
58
std::atomic_flag의 한계
• getter 가 없다.
• 값을 수정하지 않고서는 현재 값을 알아낼 수 없다.
• getter 가 필요하다면?
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
59
<atomic>
• std::atomic_flag
• std::atomic<bool>
• std::atomic<T*>
• std::atomic<int>
• std::atomic<T>
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
60
std::atomic<bool>
• 복사생성, 복사배정 불가
• 하지만 일반 bool 로부터 초기화 가능
• operator = ( ) 은 값을 리턴
• 보통은 레퍼런스를 리턴
• 수정하지 않고 읽기(load) 가능
• 이로써 일반 변수와 동일한 인터페이스 제공
• 세 종류의 read-modify-write 연산 제공
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
61
std::atomic<T> 의 read-modify-write
• T exchange(T value)
• 새 값을 쓰고, 이전 값을 리턴한다.
• bool compare_exchange_weak(T& expected, T desired)
• *this 가 expected 와 비트 단위 일치하면 *this = desired, return true
• 일치하지 않으면, expected = *this, return false (*this는 불변)
• 단, 일부 CPU에서는 *this == expected 여도 실패할 수 있다.
• bool compare_exchange_strong(T& expected, T desired)
• *this == expected 이면 실패하지 않는다.
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
62
Weak? Strong?
• 하드웨어 별 제공하는 동기화 명령
• AMD, Intel, Sun 구조 : compare-and-swap
• compare_exchange_strong() 기능을 명령어 단위 지원 (ex : cmpxchg)
• ABA문제 발생 가능
• Alpha AXP, IBM PowerPC, MIPS, ARM : load-linked, store-conditional
• load 시 변수에 침을 발라놓음.
• store 전에 다른 스레드가 해당 변수를 건드리면, store 연산이 실패
B.8 하드웨어 동기화 명령
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
63
Weak? Strong?
• LL/SC 동기화를 이용하여 compare_exchange 구현하면?
• SC가 실패하는 경우 발생 = 가짜 실패
• 가짜 실패를 용인 = compare_exchange_weak( )
• 無 가짜 실패 보장 = compare_exchange_strong( )
- 추가 처리 필요
때문에 compare_exchange_strong( ) 은
compare_exchange_weak ( ) 보다 비싸다.
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
64
그럼 ARM에서 Strong은 어떻게 구현되는지 볼까?
잉?
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
65
(적어도 VS에서는)
strong 인지 weak 인지 고민하지 않으셔도 됩니다.
그냥 strong 쓰면 됩니다.
GCC는 어떨지 궁금하네요.
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
66
compare_exchange_xx() 의 ordering
• 두 개의 ordering tag 를 파라미터로 취한다.
• 함수 호출이 성공했을 때의 ordering
• 함수 호출이 실패했을 때의 ordering
• 단, 성공했을 때보다 높은 order는 지정 불가
• 지정된 order에 따라
*this값을 얼마나 정확히(?) 읽고 쓰느냐가 달라짐
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
67
<atomic>
• std::atomic_flag
• std::atomic<bool>
• std::atomic<T*>
• std::atomic<int>
• std::atomic<T>
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
68
std::atomic<T*>
• atomic<bool> 이 지원하는 연산자 모두 지원
• std::ptrdiff_t
• 포인터 산술 연산이 가능
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
69
std::atomic<T*>::operator
• 오버로딩된 연산자에는 memory_order 지정 불가능
• 지정된 포멧이 존재하기 때문
• 무조건 std::memory_order_seq_cst
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
70
<atomic>
• std::atomic_flag
• std::atomic<bool>
• std::atomic<T*>
• std::atomic<int>
• std::atomic<T>
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
71
std::atomic<T>
• T = integral_types (ex : int)
• atomic<T*> 가 지원하는 연산자 모두 지원
• 더하기, 빼기, 증감, 비트연산 가능
• 곱하기, 나누기, 쉬프트연산 불가
• 필요하면 compare_exchange_strong()로 구현
• 주로 카운터나 비트마스크로 사용
나누기쯤 못한다고 해서 큰 문제 없음
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
72
<atomic>
• std::atomic_flag
• std::atomic<bool>
• std::atomic<T*>
• std::atomic<int>
• std::atomic<T>
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
73
generic std::atomic<T> primary class template
• T = User Defined Type
• atomic<bool> 과 같은 수준의 연산 지원
• UDT를 하나의 비트 덩어리로 인식
• UDT는 다음 조건들을 만족해야 한다.
• 비트단위 동등연산 가능 (기본 비교 연산자)
• 無 가상함수, 無 가상 베이스 클래스
• 기본 복사 배정 연산자
• 모든 non-static 멤버변수도 위 조건 만족
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
74
UDT 제약이 의미하는 것
• atomic<vector<int>> 가 불가능 하다는 것
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
75
UDT 제약이 의미하는 것
• atomic<T>의 용도
• 객체 카운터
• 플래그
• 포인터
• 간단한 데이터로 이루어진 배열
“이것보다 더 복잡한 자료구조나
더 복잡한 연산에는 뮤텍스를 쓰는 게 낫다.” – Anthony Williams
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
76
C 호환 비멤버함수
• 모든 연산에는 1:1로 동등한 비멤버 함수 존재
• 멤버함수 이름 앞에 “atomic_” 을 붙인다.
• std::atomic_store(&atomic_var, new_value)
• ordering을 추가 지정하려면 뒤에 “_explicit” 을 붙인다.
• std::atomic_store_explicit(&atomic_var, new_value, std::memory_order_release)
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
77
예외 : shared_ptr<>
• atomic 비멤버함수들의 파라미터는 atomic<T>
• 하지만 예외적으로 shared_ptr<> 도 사용 가능
C++ Concurrency in Action Study
C++ Korea
원자적 연산들과 자료형 표준 atomic type
78
계속 나오는 의문
• std::memory_order ?
• 의미론을 부여한다?
• part 3 에서 알아봅니다.
C++ Concurrency in Action Study
C++ Korea
Part 3.
Memory Ordering
79
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
80
다음 예제에서, 무엇이 출력될까요?
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
81
data
data_ready
writer_thread 가 하는 일
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
82
data
data_ready
reader_thread 가 하는 일
!
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
83
42가 출력되는 이유
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
84
42가 출력되는 이유
data를 쓰는 것은
data_ready를 쓰는 것보다
“선행”된다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
85
42가 출력되는 이유
T1이 쓴 data_ready 를
T2가 읽는다.
즉, “동기화”된다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
86
42가 출력되는 이유
data_ready를 읽는 것은
data를 읽는 것보다
“선행”된다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
87
42가 출력되는 이유
T1이 쓴 data를
T2가 읽는다.
즉, “동기화” 된다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
88
방금 본 두 가지의 개념
• 동기화 (synchronizes-with) 관계
• thread1이 쓴 data 를 thread2가 읽는 것
• “data 쓰기와 data 읽기가 동기화 된다.”
• 선행 (happens-before) 관계
• 이행 관계 성립 ( A->B 이고 B->C 이면 A->C이다. )
• “data 를 쓰는 것은 data_ready 를 쓰는 것보다 선행된다.”
• 연산들의 순서를 맞추는(강제하는) 두 가지 개념
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
89
동기화 관계
• 멀티 스레드에서만 존재
• 다음의 thread2는 어떤 값을 읽을까요?
thread 2 가 읽는 값
• 초기값인 0을 읽거나
• thread 1 이 쓴 10을 읽거나
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
90
동기화 관계
• thread 2 가 10을 읽으면, “동기화 되었다!” 라고 한다.
• write(data) 가 read(data) 보다 먼저 발생(선행) 되었으며
• write(data) 의 결과를 thread 2가 관측할 수 있었다는 의미
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
선행 관계
• 단일 스레드에서는
• 한 연산이 다른 연산보다 먼저 위치(sequenced before)해 있다면
선행(happens before)한다.
• 이미 익숙한 개념
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
92
선행 관계
• 단, 같은 구문에 위치한 연산들은 순서가 정의되지 않는다.
get_num() 은 같은 구문(statement) 에 위치
get_num() 사이엔 sequenced before 관계가 없다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
93
선행 관계
• 멀티 스레드에서는
• 스레드 간 선행 관계(inter-thread happens-before)
• 한 스레드의 연산 A가 다른 스레드의 연산 B보다 먼저 수행되면
A는 B보다 (스레드 차원에서) 선행된다.
• “동기화” 관계를 필요로 함
• 연산 A가 연산 B와 동기화 되면, A는 B보다 선행된 것이다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering the beginning
94
선행 관계의 이행성
• A->B, B->C 이면, A->C 이다.
동기화할 데이터가 여러 개더라도,
notify 는 하나로 충분
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
95
Memory Ordering 이란?
• 현대 컴파일러와 CPU는
내가 쓴 순서대로 계산하지 않는다.
누가 먼저 실행 되어도 상관없는 것들
누가 봐도 순서대로 실행되어야 할 것들
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
96
Memory Ordering 이란?
• 컴파일러 최적화의 함정
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
97
Memory Ordering 이란?
• CPU out-of-order
• 빨리 끝나도 되는 것부터 끝낸다
• 근데 싱글 스레드 기준
http://renesasrulz.com/doctor_micro/rx_blog/b/weblog/archive/2010/05/17/pipeline-and-out-of-order-instruction-execution-optimize-performance.aspx
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
98
Memory Ordering 이란?
• CPU cache & write buffer
• 계산 결과를 바로 메모리에 쓰지 않는다.
• Write Back
• 메모리 데이터 != 캐시 데이터
http://egloos.zum.com/recipes/v/5170809
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
99
Memory Ordering 이란?
• CPU cache & write buffer
in 멀티 코어
http://egloos.zum.com/recipes/v/5170809
(RAM)
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
100
Memory Ordering 이란?
• 내가 볼 땐 순서대로 실행되어야 하지만,
CPU랑 컴파일러가 볼 때에는 순서대로 실행 안되어도 상관없을 때
??
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
101
Memory Ordering 이란?
• 얼만큼 순서대로 실행해야 하는 지 알려주어야 한다
!!
1
2
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
102
Memory Ordering 이란?
• 얼만큼 순서대로 실행할 지를 단계별로 정의해 놓은 것
• relaxed “별로 순서대로 할 필요는 없어. 원자적이기만 하면 되지 뭐“
• acquire-release “적어도 너랑 나는 순서대로 쓰고 읽자“
• sequentially consistent “꼭 순서대로 읽고 써라 싱글 스레드다~ 생각하고“
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
103
Memory Ordering
비용 작음
비용 큼
약함
가장 엄중함
relaxed
acquire-release
sequentially consistent
default
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
104
Default Memory Ordering
• 가장 비싸지만, 가장 안전한 것이 default
• 지금까지 사용한 모든 atomic 연산은 seq_cst
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
105
Memory Ordering
relaxed
acquire-release
sequentially consistent
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
106
memory_order_seq_cst
• sequentially consistent
• It requires global synchronization between all threads
• 가장 강력한 제약
• 가장 비싼 비용
• 서로 다른 스레드들의 연산을 선형화 가능
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_seq_cst
107
listing 5.4
z가 0이 되는 경우가 있는가?
t1 t2
t3 t4
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_seq_cst
108
스레드 간 선행 관계
t1은 t3보다 선행
t1 t2
t3 t4
t2는 t4보다 선행
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_seq_cst
109
가능한 경우의 수
t1 t2
t3 t4
t1 t2 t3 t4 z == 2
t1 t2 t4 t3 z == 2
t1 t3 t2 t4 z == 1
t2 t1 t4 t3 z == 2
t2 t1 t3 t4 z == 2
t2 t4 t1 t3 z == 1
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_seq_cst
110
memory_order_seq_cst
• 선형화 가능
• 상식에 맞는 행동
• is_lock_free() 가 true일 때에는 lock free
• Lock 보다 빠름
결론 : seq_cst 쓰시죠
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_seq_cst
111
닝겐의 욕심은 끝이 없고…
• “난 그렇게까지 빡빡한 동기화는 필요 없는데“
• “좀 더 빠른 건 없나요?”
http://www.ddengle.com/entertainment/635506
왜 없겠어요
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_seq_cst
112
하지만 그 대가는 클 것입니다.
• seq_cst 가 없는 멀티 스레드 세상에선 그 무엇도 가능합니다
• 아까 보았던 -65535
• 0.05% 의 확률로 크래시
• 모니터 자연 발화
• relaxed ordering 을 통해 체험해봅니다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
113
Memory Ordering
relaxed
acquire-release
sequentially consistent
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
114
Listing 5.5
z는
프로그램이 끝날 때까지
0일 수 있습니다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
115
Listing 5.5 의 흐름
x.store(true, relaxed)
y.store(true, relaxed)
y.load(relaxed)
return true
x.load(relaxed)
return false ????
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
116
싱글 스레드 입장에서 생각해봅시다
x.store(true, relaxed)
y.store(true, relaxed)
y.load(relaxed)
return true
x.load(relaxed)
return false
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
117
조금 더 복잡한 예제
• Listing 5.6
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
118
가능한 결과 중 하나
t1 : (0, 0, 0), (1, 0, 0), (2, 0, 0), (3, 0, 0), (4, 0, 0), (5, 7, 0), (6, 7, 8), (7, 9, 8), (8, 9, 8), (9, 9, 10)
t2 : (0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 3, 5), (8, 4, 5), (8, 5, 5), (8, 6, 6), (8, 7, 9), (10, 8, 9), (10, 9, 10)
t3 : (0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 0, 4), (0, 0, 5), (0, 0, 6), (0, 0, 7), (0, 0, 8), (0, 0, 9)
t4 : (1, 3, 0), (2, 3, 0), (2, 4, 1), (3, 6, 4), (3, 9, 5), (5, 10, 6), (5, 10, 8), (5, 10, 10), (9, 10, 10), (10, 10, 10)
t5 : (0, 0, 0), (0, 0, 0), (0, 0, 0), (6, 3, 7), (6, 5, 7), (7, 7, 7), (7, 8, 7), (8, 8, 7), (8, 8, 9), (8, 8, 9)
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
119
relaxed order 의 이해
• 책에 나온 설명
5
note
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
120
Store
5
10
note
10 저장 좀
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
121
Store
5
10
23
3
1
2
42
note
23 저장 좀
3 저장 좀
1 저장 좀
2 저장 좀
42 저장 좀
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
122
Load
5
10
23
3
1
2
42
note
23 저장 좀
3 저장 좀
1 저장 좀
2 저장 좀
42 저장 좀
지금 값 뭐?
어떤 수를 알려 줘야 할까?
?
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
123
우리의 입장
• 당연히 42
5
10
23
3
1
2
42
note 이거
찾으시죠?
ㄳ
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
124
큐빅맨의 입장
• note 에 쓰여진 값 중 어떤 값이라도 전달 가능
5
10
23
3
1
2
42
note 뭐가 최신인지
내가 어떻게 알아
걍 주는대로 받아
네 中 1개
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
125
Reload
5
10
23
3
1
2
42
note
그럼
지금은
값 뭐임?
한번 더, 어떤 수를 알려 줘야 할까?
또?
이전 값
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
126
Reload
• 전에 알려줬던 값보다 더 과거의 값을 알려주진 않는다.
5
10
23
3
1
2
42
note
옛날 값 주면
욕 먹겠지?이전 값
中 1개
굳
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
127
Listing 5.5 다시 생각해봅시다.
x.store(true, relaxed)
y.store(true, relaxed)
y.load(relaxed)
return true
x.load(relaxed)
return false
x
y
x 와 y는 서로 다른 큐빅맨
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
128
memory_order_relaxed
• relaxed order 는 순서 제약이 없으므로 빠르다.
하지만
• 비직관적이고, 다루기 어렵다.
• 반드시 더 강한 ordering 과 함께 사용해야 한다.
“I strongly recommend avoiding relaxed atomic operations
unless they’re absolutely necessary”
– Anthony Williams
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_relaxed
129
대안은 없을까?
• seq_cst 보다 빠르면서
• relaxed 보다 쎈 거
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
130
Memory Ordering
relaxed
acquire-release
sequentially consistent
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
131
Listing 5.7
t1 t2
t4t3
z는 0일 수 있을까?
쓰기용
읽기용
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
132
불행히도 relaxed 랑 똑같습니다.
t1 t2
t4t3
선행 관계 아님
x == true 여도,
y == false 일 수 있음
y == true 여도,
x == false 일 수 있음
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
133
acquire-release 의 한계
• 서로 다른 스레드에서 write -> 수정 순서를 보지 못한다.
• Listing 5.7의 assert가 안뜨게 하려면 seq_cst 를 써야함
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
134
그럼 acquire-release 가 해주는 게 뭔가요
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
135
Listing 5.8
여기서는 z가 0이 되지 않습니다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
136
memory_order_acquire / _release
• release 로 쓴 변수를
• acquire 로 읽으면
• 쓰기와 읽기가 동기화
• 스레드 간 선행 관계가 성립한다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
137
Listing 5.8 다시보기
x.store(true, relaxed)
y.store(true, release)
y.load(acquire)
return true
x.load(relaxed)
return true
선행관계
성립
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
138
acquire-release 의 이해
1p
2p
3p
note
노트는 사실
여러 페이지
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
139
release 의미론으로 쓴다는 의미
x
y
x 야.
1페이지에
true 저장해줘.
false
false
true
y 야.
1페이지에
true 저장해줘.
근데 이게
마지막이야
true
true를 쓰고
페이지를 넘김
종이 아깝게
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
140
acquire 의미론으로 읽는다는 의미
x
y
false
false
true
true
y 야.
지금 값 뭐니?
(뒷돈을 건네며)
이게
이번 페이지
마지막 값이야
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
141
acquire 이후의 relaxed 읽기
x
y
false
false
true
true
x 야.
지금 값 뭐니?
다 알고 왔다.
귀찮게
찾아야 하잖아
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
142
memory_order_acquire / _release
• 항상 최신 값을 주는 게 아님
• y 가 true임을 읽었을 때,
그 위에 있던 x.store(true, relaxed) 가 선행되었음을 보장
• 즉, 순서가 뒤바뀌지 않았음을 보장
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
143
acquire-release 의 이행성
• a->b, b->c 이므로 a->c
x.store() -> y.store(), y.store() -> y.load(), y.load() -> x.load()
이므로
x.store() -> x.load()
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
144
acquire-release 의 이행성
x.store(true, relaxed)
y.store(true, release)
y.load(acquire)
return true
x.load(relaxed)
return true
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_acquire / _release
145
acquire-release 의 이행성
x.store(true, relaxed)
y.store(true, release)
z.load(acquire)
return true
x.load(relaxed)
return true
y.load(acquire)
return true
z.store(true, release)
C++ Concurrency in Action Study
C++ Korea
Memory Ordering memory_order_consume / _release
146
memory_order_consume
• 동기화할 데이터는 하나로 충분할 때
• release로 저장된 변수의 데이터 의존성을 다른 스레드로 전달
• 의존성이 없는 변수는 선행관계 x
k = 11;
b = 1;
e = b+10;
a.store(e, release)
x = 0;
while(x = a.load(consume)); // x == e, b == 1 보장
y = x – 10;
x = y + 1;
t = k; // 선행관계 아님
저보다 훠어어얼씬 더 잘 설명해준 슬라이드
http://www.slideshare.net/YiHsiuHsu/introduction-to-memory-order-consume
C++ Concurrency in Action Study
C++ Korea
Memory Ordering relaxed and acquire-release
147
relaxed 와 acquire / release 비교
• Listing 5.5
• relaxed 일 때
• acquire-release 일 때
왜 둘 다 에러가 안 나지?
C++ Concurrency in Action Study
C++ Korea
Memory Ordering relaxed and acquire-release
148
relaxed 와 acquire / release 가 차이가 없는 이유
Microsoft : 우리 컴파일러는 volatile 이면
acquire / release 임 ㅋ
ISO : …
https://msdn.microsoft.com/ko-kr/library/12a04hfd.aspx
C++ Concurrency in Action Study
C++ Korea
Memory Ordering relaxed and acquire-release
149
/volatile:iso 로 바꾸어보자
프로젝트 속성
그런데 이래도 Listing 5.5 는 잘 돕니다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering relaxed and acquire-release
150
relaxed 와 acquire / release 가 차이가 없는 이유2
Intel : 우린 일반 변수도 acquire / release 임 ㅋ
ARM : …
ISO : …
MS : 헐 ㅋ 굳 ㅋ
C++ Concurrency in Action Study
C++ Korea
Memory Ordering relaxed and acquire-release
151
어떤 차이가 있길래?
• Reordering 을 어떻게 하느냐의 차이!
• 그런데 Reordering이 무언가요
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
152
Reordering 종류
Load Load Load Store
Store Load Store Store
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
153
아키텍쳐 별 Reordering
Load Load Load Store
Store Load Store Store
x86은 Store Load 일 때에만 reordering
ARM은 네 경우 모두 reordering
https://en.wikipedia.org/wiki/Memory_ordering
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
154
x86-64 에서는?
Intel 64-ia-32 architectures
software developer system programming manual volume 3
x86-64도 Store Load 일 때에만 reordering
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
155
이제 이렇게 부릅시다.
인텔은 Store Load 일 때에만 reordering Strong Memory Models
ARM은 네 경우 모두 reordering Weak With Data Dependency Ordering
http://preshing.com/20120930/weak-vs-strong-memory-models/
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
156
x86 이나 x86-64 아키텍쳐
intel 이나 amd 같은 PC에서 일반적으로 사용하는 cpu는
acquire-release 이하의 의미론을 사용하는 데
추가적인 명령어가 필요 없다.
(즉, 일반 변수도 acquire-release)
seq_cst 에 약간의 추가적인 store 비용이 들 뿐이다.
하지만 ARM 이나 PowerPC 에서는 차이가 크다.
-Anthony Williams
본문에는 이렇게 설명되어 있습니다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
157
http://www.slideshare.net/YiHsiuHsu/introduction-to-memory-order-consume
차이가 얼마나 큼?
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
158
Reordering 이랑
C++ Memory Ordering 이랑 무슨 상관인가요?
Load Load Load Store
Store Load Store Store
memory_order_seq_cst
memory_order_release
memory_order_acquire
memory_order_relaxed
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
159
Load Load Load Store
Store Load Store Store
Reordering 과 C++ Memory Ordering 의 상관관계
x.store(true, relaxed)
y.store(true, release)
y.load(acquire)
return true
x.load(relaxed)
return true
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
160
Load Load Load Store
Store Load Store Store
Reordering 과 C++ Memory Ordering 의 상관관계
x.store(true, relaxed)
y.store(true, release)
y.load(acquire)
return true
x.load(relaxed)
return true
낚이지 마세요.
이렇게는 Store Load
고려 대상이 아닙니다.
스레드가 다르니까요.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
161
Load Load Load Store
Store Load Store Store
Reordering 과 C++ Memory Ordering 의 상관관계
x.store(true, relaxed)
y.store(true, release)
y.load(acquire)
return true
x.load(relaxed)
return true
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
162
Load Load Load Store
Store Load Store Store
Reordering 과 C++ Memory Ordering 의 상관관계
x.store(true, relaxed)
y.store(true, release)
z.load(acquire)
return true
x.load(relaxed)
return true
y.load(acquire)
return true
z.store(true, release)
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
163
아직 한 발 남았습니다.
Store Load
x86-64 에서는 Reordering에 의한 버그는 못보나요?
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
164
피터슨 알고리즘
http://www.slideshare.net/deview/242-naver2?qid=79a97d1c-4ba8-4c89-bda5-2e1387e6e1e6&v=qf1&b=&from_search=4
http://www.slideshare.net/zzapuno/kgc2013-3?qid=9e511612-d469-47cd-96cd-b6a0a623fd9e&v=qf1&b=&from_search=1
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
165
seq_cst 말고는 답이 없는가?
• 우리가 reordering 을 막을 방법은 정녕 없는 것인가요?
C++ Concurrency in Action Study
C++ Korea
Memory Ordering reordering
166
memory fence
• 위 연산의 결과가 메모리에 모두 쓰여질 때까지
• 다음 명령어를 실행하지 않는다.
C++ Concurrency in Action Study
C++ Korea
Memory Ordering for atomic operation
167
Listing 5.13
• fence를 사용하여 동기화하기
• C++11 : std::atomic_thread_fence()
• (주의) ++a 를 mfence 로 감싼다고 아토믹이 되는 것은 아님
C++ Concurrency in Action Study
C++ Korea
Summury
168
결론
• Data Race 를 없애기 위해 atomic<T> 을 사용
• 복잡한 알고리즘에는 Lock을 사용
• 성능 향상을 위해 memory ordering 직접 지정
• CPU 아키텍처 별로 고려해야 할 정도가 다름
• fence를 이용해 reordering을 막을 수 있음
C++ Concurrency in Action Study
C++ Korea
감사합니다.
C++ Concurrency in Action Study
C++ Korea
Reference
170
http://preshing.com/20120930/weak-vs-strong-memory-models/
http://www.slideshare.net/deview/242-naver2?qid=3b220326-f8fb-4392-9b5f-0efe29d7823c&v=default&b=&from_search=4
http://www.slideshare.net/zzapuno/kgc2013-3?qid=9e511612-d469-47cd-96cd-b6a0a623fd9e&v=qf1&b=&from_search=1
http://www.slideshare.net/YiHsiuHsu/introduction-to-memory-order-consume
https://en.wikipedia.org/wiki/Memory_ordering
http://en.cppreference.com/w/cpp/atomic/
http://egloos.zum.com/recipes/v/5170809
멀티프로세서 프로그래밍 (The Art of Multiprocessor Programming) – 모리스 헐리히, 니르 샤비트 / 김진욱, 하재승 역
C++ concurrency in action – Anthony Williams
Intel 64-ia-32 architectures software developer system programming manual volume 3

More Related Content

PPT
Multithread & shared_ptr
PDF
Lock free queue
PPTX
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
PDF
임태현, 게임 서버 디자인 가이드, NDC2013
PDF
실시간 게임 서버 최적화 전략
PDF
Iocp advanced
PDF
Iocp 기본 구조 이해
PDF
Windows Registered I/O (RIO) vs IOCP
Multithread & shared_ptr
Lock free queue
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
임태현, 게임 서버 디자인 가이드, NDC2013
실시간 게임 서버 최적화 전략
Iocp advanced
Iocp 기본 구조 이해
Windows Registered I/O (RIO) vs IOCP

What's hot (20)

PDF
Ndc2014 시즌 2 : 멀티쓰레드 프로그래밍이 왜 이리 힘드나요? (Lock-free에서 Transactional Memory까지)
PDF
NDC12_Lockless게임서버설계와구현
PDF
게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델
PDF
〈야생의 땅: 듀랑고〉 서버 아키텍처 Vol. 3
PDF
MMOG Server-Side 충돌 및 이동처리 설계와 구현
PDF
임태현, MMO 서버 개발 포스트 모템, NDC2012
PDF
LockFree Algorithm
PDF
테라로 살펴본 MMORPG의 논타겟팅 시스템
PDF
[야생의 땅: 듀랑고] 서버 아키텍처 Vol. 2 (자막)
PPTX
게임 분산 서버 구조
PDF
양승명, 다음 세대 크로스플랫폼 MMORPG 아키텍처, NDC2012
PPTX
윤석주, 신입 게임 프로그래머가 되는 법 - 넥슨 채용 프로세스 단계별 분석, NDC2019
PDF
게임서버프로그래밍 #1 - IOCP
PDF
[NDC2016] TERA 서버의 Modern C++ 활용기
PPTX
Windows system - memory개념잡기
PDF
Multiplayer Game Sync Techniques through CAP theorem
PDF
이승재, 실버바인 서버엔진 2 설계 리뷰, NDC2018
PPTX
스마트폰 온라인 게임에서 고려해야 할 것들
PDF
시즌 2: 멀티쓰레드 프로그래밍이 왜이리 힘드나요?
PPTX
KGC 2014: 분산 게임 서버 구조론
Ndc2014 시즌 2 : 멀티쓰레드 프로그래밍이 왜 이리 힘드나요? (Lock-free에서 Transactional Memory까지)
NDC12_Lockless게임서버설계와구현
게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델
〈야생의 땅: 듀랑고〉 서버 아키텍처 Vol. 3
MMOG Server-Side 충돌 및 이동처리 설계와 구현
임태현, MMO 서버 개발 포스트 모템, NDC2012
LockFree Algorithm
테라로 살펴본 MMORPG의 논타겟팅 시스템
[야생의 땅: 듀랑고] 서버 아키텍처 Vol. 2 (자막)
게임 분산 서버 구조
양승명, 다음 세대 크로스플랫폼 MMORPG 아키텍처, NDC2012
윤석주, 신입 게임 프로그래머가 되는 법 - 넥슨 채용 프로세스 단계별 분석, NDC2019
게임서버프로그래밍 #1 - IOCP
[NDC2016] TERA 서버의 Modern C++ 활용기
Windows system - memory개념잡기
Multiplayer Game Sync Techniques through CAP theorem
이승재, 실버바인 서버엔진 2 설계 리뷰, NDC2018
스마트폰 온라인 게임에서 고려해야 할 것들
시즌 2: 멀티쓰레드 프로그래밍이 왜이리 힘드나요?
KGC 2014: 분산 게임 서버 구조론
Ad

Similar to [C++ Korea] C++ 메모리 모델과 atomic 타입 연산들 (20)

PDF
Concurrency in action - chapter 5
PDF
[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요
PPTX
Visual C++10을 활용한 병렬 프로그래밍
PDF
242 naver-2
PDF
C++ Concurrency in Action 9-2 Interrupting threads
PDF
(2013 DEVIEW) 멀티쓰레드 프로그래밍이 왜이리 힘드나요?
PPTX
Concurrent programming
PPTX
Effective c++ Chapter1,2
PDF
C++20 Key Features Summary
PPTX
tcp ip study
PPTX
C++11에서 주의해야할 것들
PPTX
2015 제2회 동아리 해커 세미나 - 병렬컴퓨팅 소개 (16기 김정현)
PPTX
About Visual C++ 10
PDF
7 8 1
PPTX
동기화, 스케줄링
PDF
Modern C++ 프로그래머를 위한 CPP11/14 핵심
PPTX
면접 대비 벡터, CS 개념과 사례
PDF
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
PPTX
A tour of C++ : the basics
PPTX
C++ 개요와 표준안
Concurrency in action - chapter 5
[2B7]시즌2 멀티쓰레드프로그래밍이 왜 이리 힘드나요
Visual C++10을 활용한 병렬 프로그래밍
242 naver-2
C++ Concurrency in Action 9-2 Interrupting threads
(2013 DEVIEW) 멀티쓰레드 프로그래밍이 왜이리 힘드나요?
Concurrent programming
Effective c++ Chapter1,2
C++20 Key Features Summary
tcp ip study
C++11에서 주의해야할 것들
2015 제2회 동아리 해커 세미나 - 병렬컴퓨팅 소개 (16기 김정현)
About Visual C++ 10
7 8 1
동기화, 스케줄링
Modern C++ 프로그래머를 위한 CPP11/14 핵심
면접 대비 벡터, CS 개념과 사례
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
A tour of C++ : the basics
C++ 개요와 표준안
Ad

[C++ Korea] C++ 메모리 모델과 atomic 타입 연산들

  • 1. C++ Concurrency in Action Study C++ Korea C++ Korea C++ Concurrency in Action Study C++ Korea 박 동하 (luncliff@gmail.com) C++ Korea 최 동민 (dongminchoi90@gmail.com)
  • 2. C++ Concurrency in Action Study C++ Korea 지난 이야기(4장) 2 • 조건 변수 • future • promise • async • packaged_task • shared_future • 시간 측정 • chrono • Using synchronization of operations to simplify code • 함수형 프로그래밍 • Communicating Sequential Process
  • 3. C++ Concurrency in Action Study C++ Korea 오늘의 내용
  • 4. C++ Concurrency in Action Study C++ Korea Part 1. 메모리 모델 기초 4
  • 5. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 5 객체지향을 처음 배울 때 Q. 객체란 무엇인지 쓰시오. (1점)
  • 6. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 6 C++ 의 모든 데이터 : “객체” • “모든 것은 객체이다.” - by Ruby or SmallTalk • “객체란 메모리 공간의 한 영역이다.” - by C++ 표준 • 객체란 단지 만들어진 데이터 블록의 상태를 의미.
  • 7. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 7 객체란 메모리 공간의 한 영역
  • 8. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 8 우리가 이미 알고 있는 것 다른 스레드가 같은 객체를 접근하면 Data Race
  • 9. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 9 우리가 이미 알고 있는 것 다른 스레드가 같은 객체를 접근하면 Data Race ?
  • 10. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 10 객체는 메모리 안의 특정 공간에 저장 • 한 객체는 기본적으로 최소한 하나의 메모리 공간 차지 • 기본형(POD)들은 정확히 하나의 메모리 공간 차지 • 인접해 있거나, 배열의 원소이더라도 • 단, 인접한 비트 필드 (Adjacent bit fields)는 하나의 메모리 블록으로 취급
  • 11. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 11 #progma pack(4) 일 때 이 구조체의 필드는 메모리에 어떻게 잡힐까요?
  • 12. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 12 책에 나온 해답 한 메모리 공간에 두 객체
  • 13. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 13 테스트 환경 : VS2015 Update 1, 32bit App, Debug 실제로 해보니, 다른 메모리 공간에 할당
  • 14. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 14 합이 32bit 초과. -> 쪼갠다. 합이 32bit 이하. -> 합친다. 테스트 환경 : VS2015 Update 1, 32bit App, Debug 같은 메모리 공간에 할당
  • 15. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 15 같은 메모리 공간에 할당
  • 16. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 16 이것이 왜 중요한가? 문제 없음
  • 17. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 17 이것이 왜 중요한가? Data Race!
  • 18. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 18 같은 메모리 공간을 접근
  • 19. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 19 같은 메모리 공간을 접근한 결과 ‘인접한 비트 필드’의 경우, 심지어 다른 객체를 참조했음에도 Data Race Data Race 는 곧 미정의 동작(Undefined Behavior)
  • 20. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 20 미정의 동작(Undefined Behavior) • C++의 가장 끔찍한 부분 중 하나 • 한 번 일어나면, 그 어플리케이션은 망한 거나 다름 없음. • 어떠한 일이라도 일어날 수 있음. • “제가 알고 있는 미정의 동작 중 하나는 당신의 모니터에 갑자기 불이 붙는 것입니다.” – Anthony Williams
  • 21. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 21 동공 지진
  • 22. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 객체와 메모리 공간 22 하지만 우리는 이 끔찍한 길을 걷기로 다짐했습니다. • Data Race 가 있는 메모리 공간에 접근 시 원자적 연산을 사용 • Data Race 를 근본적으로 막을 수는 없지만, 프로그램을 정의된 동작으로 되돌릴 수 있다.
  • 23. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 수정 순서 23 또 하나 알아야 할 개념 : 수정 순서 (Modification Orders) • 쓰기 순서(write order) 라고도 함 • 한 객체에 대한 모든 쓰기 연산에 순서를 정의한 것 • 오직 한 순간에, 하나의 쓰기만이 허용된다고 가정 • 모든 스레드에서, 이 순서는 일치해야 함.
  • 24. C++ Concurrency in Action Study C++ Korea24 수정 순서 write(3) write(10) write(-1) 초기값:0 i 의 변천사 0 3 -1 10 메모리 모델 기초 수정 순서
  • 25. C++ Concurrency in Action Study C++ Korea25 스레드가 보는 수정 순서 메모리 모델 기초 수정 순서 이 보는 i 의 변천사 0 3 10 가 보는 i 의 변천사 0 3 -1 10 ??-65535
  • 26. C++ Concurrency in Action Study C++ Korea26 메모리 모델 기초 수정 순서
  • 27. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 수정 순서 27 우리가 원하는 것 • Data Race 로 인한 미정의 동작을 피하고 싶다. • 서로 다른 스레드에서 보는 수정 순서를 맞추고 싶다.
  • 28. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 수정 순서 28 누구의 책임인가? • 컴파일러, CPU는 기본적으로 멀티 스레드에 대한 책임이 없다. • 싱글 스레드 단위로 판단 • 우리가 해야 할 일 • 적절한 원자적 연산을 사용해서, 컴파일러에게 수정 순서를 맞추라고 알려주는 것. • 원자적 연산 사용 시 • 컴파일러는 필요한 동기화를 필요한 위치에 넣을 책임을 지게 된다.
  • 29. C++ Concurrency in Action Study C++ Korea 메모리 모델 기초 수정 순서 29 원자적 연산을 쓰면 되는군요! • 그런데 이게 무엇인지? • 어떤 연산들이 있는지? • 어떨 때 써야 하는지? • 어디에 써야 하는지? • Part2 에서 알아봅시다.
  • 30. C++ Concurrency in Action Study C++ Korea Part 2. C++에서의 원자적 연산들과 자료형 30
  • 31. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 31 1 + 1 = 1? !!
  • 32. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 32 원자적 연산이란? • 더 이상 나눌 수 없는 연산 • 연산이 반만 된 상태를 관측할 수 없음
  • 33. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 33 비원자적 연산 • ++a;
  • 34. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 34 비원자적 연산 • ++a 를 두 스레드에서 동시에 실행할 경우
  • 35. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 35 원자적 연산 • ++a;
  • 36. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 36 원자적 연산 • InterlockedExchange InterlockedAdd … • 이게 C++ 표준 인가요?
  • 37. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 37 표준 atomic types • #include<atomic> • 표준에서는, 오로지 이 타입들의 연산만이 원자적. • 아니면 lock을 사용해서 “원자적으로 보이게“ 해야 함. • is_lock_free() 멤버함수를 가짐.
  • 38. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 38 Lock Free 가 뭔가요? 락으로부터 자유롭나?
  • 39. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 39 Lock Free(무잠금) 란? • Lock 없이 연산을 즉시 완료할 수 있으면 Lock Free! • 뮤텍스나 Critical Section 같은 “Lock” 은 획득하지 못했을 시 스레드의 Sleep을 유발 -> 성능에 치명적 • Lock 은 적을 수록 좋다. 대표 함수 – InterlockedAdd(), InterlockedExchange(), InterlockedCompareExchange()
  • 40. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 40 Lock Free 구현 • 하드웨어 지원 • 명령어 존재. 실패할 일 없음. • 소프트웨어 구현 • 명령어로는 지원할 수 없는 복잡한 알고리즘의 경우 직접 구현 필요 • Compare And Swap(CAS) 로 구현 • PASS. 다음 챕터 분들께 양도합니다.
  • 41. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 41 atomic<T>::is_lock_free()
  • 42. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 42 이게 무슨 원리래요
  • 43. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 43 is_lock_free() 구현 VS2013, 2015에서는 8바이트 이하의 객체면 Lock-Free
  • 44. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 44 8byte 초과 시 짤없음
  • 45. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 45 Lock Free 가 아니면?
  • 46. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 46 8byte 초과 Type atomic<Type>::store() 내부구현
  • 47. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 47 8byte 초과 시 Lock 음 스핀락이군요
  • 48. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 48 8byte 초과 시 Lock? 음 스핀락이군요 잉???
  • 49. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 49 8byte 초과 시 Lock • 당황스럽긴 하지만, 정상적인 구현 • “memcpy() 쯤이야 오래 걸려봤자 얼마나 걸린다고..” • 언젠가는 락을 가져오는데 성공한다. • atomic<T> 가 지원하는 연산 중 복잡한 로직이 없기 때문에 가능한 구현. ex : “컨테이너에서 유저를 찾아서 현재 체력이 0 이하면 마을로 귀환“ 이런 거 못함.
  • 50. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 50 다시 본론으로 돌아갑니다. • atomic<T> 클래스를 보고 있었죠?
  • 51. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 51 <atomic> • std::atomic_flag • 반드시 lock-free • test_and_set() or clear() 만 가능한 BOOL • std::atomic<T> • T 타입에 따라, 다른 연산자 제공 • lock-free가 아닐 수도 있음 • 아무 클래스나 T에 넣을 수는 없음. 제약이 존재.
  • 52. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 52 <atomic> • std::atomic_flag • std::atomic<bool> • std::atomic<T*> • std::atomic<int> • std::atomic<T>
  • 53. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 53 <atomic> • std::atomic_flag • std::atomic<bool> • std::atomic<T*> • std::atomic<int> • std::atomic<T>
  • 54. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 54 std::atomic_flag • 반드시 초기화 필요 • ATOMIC_FLAG_INIT • 파라미터로 memory order 지정. • clear(std::memory_order_release) “이 변수를 초기화할 때 release 의미론을 사용하라” • 디폴트는 std::memory_order_seq_cst • 가장 강력한 의미론. 선형화 • 조금 있다 자세히
  • 55. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 55 std::atomic_flag • bool atomic_flag::test_and_set() • 변수가 현재 true 이면, 그냥 true를 리턴 • 변수가 현재 false 이면, 값을 true로 바꾸고 이전 값인 false 리턴 • 용례 • Spin Lock
  • 56. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 56 std::atomic_flag • 방금 보았던 8byte 초과 atomic<T> 타입의 내부 스핀락
  • 57. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 57 std::atomic_flag 를 이용한 spinlock mutex 구현 “바쁜 대기라 좋은 선택은 아니지만, 상호 배제를 보장하긴 합니다”
  • 58. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 58 std::atomic_flag의 한계 • getter 가 없다. • 값을 수정하지 않고서는 현재 값을 알아낼 수 없다. • getter 가 필요하다면?
  • 59. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 59 <atomic> • std::atomic_flag • std::atomic<bool> • std::atomic<T*> • std::atomic<int> • std::atomic<T>
  • 60. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 60 std::atomic<bool> • 복사생성, 복사배정 불가 • 하지만 일반 bool 로부터 초기화 가능 • operator = ( ) 은 값을 리턴 • 보통은 레퍼런스를 리턴 • 수정하지 않고 읽기(load) 가능 • 이로써 일반 변수와 동일한 인터페이스 제공 • 세 종류의 read-modify-write 연산 제공
  • 61. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 61 std::atomic<T> 의 read-modify-write • T exchange(T value) • 새 값을 쓰고, 이전 값을 리턴한다. • bool compare_exchange_weak(T& expected, T desired) • *this 가 expected 와 비트 단위 일치하면 *this = desired, return true • 일치하지 않으면, expected = *this, return false (*this는 불변) • 단, 일부 CPU에서는 *this == expected 여도 실패할 수 있다. • bool compare_exchange_strong(T& expected, T desired) • *this == expected 이면 실패하지 않는다.
  • 62. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 62 Weak? Strong? • 하드웨어 별 제공하는 동기화 명령 • AMD, Intel, Sun 구조 : compare-and-swap • compare_exchange_strong() 기능을 명령어 단위 지원 (ex : cmpxchg) • ABA문제 발생 가능 • Alpha AXP, IBM PowerPC, MIPS, ARM : load-linked, store-conditional • load 시 변수에 침을 발라놓음. • store 전에 다른 스레드가 해당 변수를 건드리면, store 연산이 실패 B.8 하드웨어 동기화 명령
  • 63. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 63 Weak? Strong? • LL/SC 동기화를 이용하여 compare_exchange 구현하면? • SC가 실패하는 경우 발생 = 가짜 실패 • 가짜 실패를 용인 = compare_exchange_weak( ) • 無 가짜 실패 보장 = compare_exchange_strong( ) - 추가 처리 필요 때문에 compare_exchange_strong( ) 은 compare_exchange_weak ( ) 보다 비싸다.
  • 64. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 64 그럼 ARM에서 Strong은 어떻게 구현되는지 볼까? 잉?
  • 65. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 65 (적어도 VS에서는) strong 인지 weak 인지 고민하지 않으셔도 됩니다. 그냥 strong 쓰면 됩니다. GCC는 어떨지 궁금하네요.
  • 66. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 66 compare_exchange_xx() 의 ordering • 두 개의 ordering tag 를 파라미터로 취한다. • 함수 호출이 성공했을 때의 ordering • 함수 호출이 실패했을 때의 ordering • 단, 성공했을 때보다 높은 order는 지정 불가 • 지정된 order에 따라 *this값을 얼마나 정확히(?) 읽고 쓰느냐가 달라짐
  • 67. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 67 <atomic> • std::atomic_flag • std::atomic<bool> • std::atomic<T*> • std::atomic<int> • std::atomic<T>
  • 68. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 68 std::atomic<T*> • atomic<bool> 이 지원하는 연산자 모두 지원 • std::ptrdiff_t • 포인터 산술 연산이 가능
  • 69. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 69 std::atomic<T*>::operator • 오버로딩된 연산자에는 memory_order 지정 불가능 • 지정된 포멧이 존재하기 때문 • 무조건 std::memory_order_seq_cst
  • 70. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 70 <atomic> • std::atomic_flag • std::atomic<bool> • std::atomic<T*> • std::atomic<int> • std::atomic<T>
  • 71. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 71 std::atomic<T> • T = integral_types (ex : int) • atomic<T*> 가 지원하는 연산자 모두 지원 • 더하기, 빼기, 증감, 비트연산 가능 • 곱하기, 나누기, 쉬프트연산 불가 • 필요하면 compare_exchange_strong()로 구현 • 주로 카운터나 비트마스크로 사용 나누기쯤 못한다고 해서 큰 문제 없음
  • 72. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 72 <atomic> • std::atomic_flag • std::atomic<bool> • std::atomic<T*> • std::atomic<int> • std::atomic<T>
  • 73. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 73 generic std::atomic<T> primary class template • T = User Defined Type • atomic<bool> 과 같은 수준의 연산 지원 • UDT를 하나의 비트 덩어리로 인식 • UDT는 다음 조건들을 만족해야 한다. • 비트단위 동등연산 가능 (기본 비교 연산자) • 無 가상함수, 無 가상 베이스 클래스 • 기본 복사 배정 연산자 • 모든 non-static 멤버변수도 위 조건 만족
  • 74. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 74 UDT 제약이 의미하는 것 • atomic<vector<int>> 가 불가능 하다는 것
  • 75. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 75 UDT 제약이 의미하는 것 • atomic<T>의 용도 • 객체 카운터 • 플래그 • 포인터 • 간단한 데이터로 이루어진 배열 “이것보다 더 복잡한 자료구조나 더 복잡한 연산에는 뮤텍스를 쓰는 게 낫다.” – Anthony Williams
  • 76. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 76 C 호환 비멤버함수 • 모든 연산에는 1:1로 동등한 비멤버 함수 존재 • 멤버함수 이름 앞에 “atomic_” 을 붙인다. • std::atomic_store(&atomic_var, new_value) • ordering을 추가 지정하려면 뒤에 “_explicit” 을 붙인다. • std::atomic_store_explicit(&atomic_var, new_value, std::memory_order_release)
  • 77. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 77 예외 : shared_ptr<> • atomic 비멤버함수들의 파라미터는 atomic<T> • 하지만 예외적으로 shared_ptr<> 도 사용 가능
  • 78. C++ Concurrency in Action Study C++ Korea 원자적 연산들과 자료형 표준 atomic type 78 계속 나오는 의문 • std::memory_order ? • 의미론을 부여한다? • part 3 에서 알아봅니다.
  • 79. C++ Concurrency in Action Study C++ Korea Part 3. Memory Ordering 79
  • 80. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 80 다음 예제에서, 무엇이 출력될까요?
  • 81. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 81 data data_ready writer_thread 가 하는 일
  • 82. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 82 data data_ready reader_thread 가 하는 일 !
  • 83. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 83 42가 출력되는 이유
  • 84. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 84 42가 출력되는 이유 data를 쓰는 것은 data_ready를 쓰는 것보다 “선행”된다.
  • 85. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 85 42가 출력되는 이유 T1이 쓴 data_ready 를 T2가 읽는다. 즉, “동기화”된다.
  • 86. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 86 42가 출력되는 이유 data_ready를 읽는 것은 data를 읽는 것보다 “선행”된다.
  • 87. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 87 42가 출력되는 이유 T1이 쓴 data를 T2가 읽는다. 즉, “동기화” 된다.
  • 88. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 88 방금 본 두 가지의 개념 • 동기화 (synchronizes-with) 관계 • thread1이 쓴 data 를 thread2가 읽는 것 • “data 쓰기와 data 읽기가 동기화 된다.” • 선행 (happens-before) 관계 • 이행 관계 성립 ( A->B 이고 B->C 이면 A->C이다. ) • “data 를 쓰는 것은 data_ready 를 쓰는 것보다 선행된다.” • 연산들의 순서를 맞추는(강제하는) 두 가지 개념
  • 89. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 89 동기화 관계 • 멀티 스레드에서만 존재 • 다음의 thread2는 어떤 값을 읽을까요? thread 2 가 읽는 값 • 초기값인 0을 읽거나 • thread 1 이 쓴 10을 읽거나
  • 90. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 90 동기화 관계 • thread 2 가 10을 읽으면, “동기화 되었다!” 라고 한다. • write(data) 가 read(data) 보다 먼저 발생(선행) 되었으며 • write(data) 의 결과를 thread 2가 관측할 수 있었다는 의미
  • 91. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 선행 관계 • 단일 스레드에서는 • 한 연산이 다른 연산보다 먼저 위치(sequenced before)해 있다면 선행(happens before)한다. • 이미 익숙한 개념
  • 92. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 92 선행 관계 • 단, 같은 구문에 위치한 연산들은 순서가 정의되지 않는다. get_num() 은 같은 구문(statement) 에 위치 get_num() 사이엔 sequenced before 관계가 없다.
  • 93. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 93 선행 관계 • 멀티 스레드에서는 • 스레드 간 선행 관계(inter-thread happens-before) • 한 스레드의 연산 A가 다른 스레드의 연산 B보다 먼저 수행되면 A는 B보다 (스레드 차원에서) 선행된다. • “동기화” 관계를 필요로 함 • 연산 A가 연산 B와 동기화 되면, A는 B보다 선행된 것이다.
  • 94. C++ Concurrency in Action Study C++ Korea Memory Ordering the beginning 94 선행 관계의 이행성 • A->B, B->C 이면, A->C 이다. 동기화할 데이터가 여러 개더라도, notify 는 하나로 충분
  • 95. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 95 Memory Ordering 이란? • 현대 컴파일러와 CPU는 내가 쓴 순서대로 계산하지 않는다. 누가 먼저 실행 되어도 상관없는 것들 누가 봐도 순서대로 실행되어야 할 것들
  • 96. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 96 Memory Ordering 이란? • 컴파일러 최적화의 함정
  • 97. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 97 Memory Ordering 이란? • CPU out-of-order • 빨리 끝나도 되는 것부터 끝낸다 • 근데 싱글 스레드 기준 http://renesasrulz.com/doctor_micro/rx_blog/b/weblog/archive/2010/05/17/pipeline-and-out-of-order-instruction-execution-optimize-performance.aspx
  • 98. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 98 Memory Ordering 이란? • CPU cache & write buffer • 계산 결과를 바로 메모리에 쓰지 않는다. • Write Back • 메모리 데이터 != 캐시 데이터 http://egloos.zum.com/recipes/v/5170809
  • 99. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 99 Memory Ordering 이란? • CPU cache & write buffer in 멀티 코어 http://egloos.zum.com/recipes/v/5170809 (RAM)
  • 100. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 100 Memory Ordering 이란? • 내가 볼 땐 순서대로 실행되어야 하지만, CPU랑 컴파일러가 볼 때에는 순서대로 실행 안되어도 상관없을 때 ??
  • 101. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 101 Memory Ordering 이란? • 얼만큼 순서대로 실행해야 하는 지 알려주어야 한다 !! 1 2
  • 102. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 102 Memory Ordering 이란? • 얼만큼 순서대로 실행할 지를 단계별로 정의해 놓은 것 • relaxed “별로 순서대로 할 필요는 없어. 원자적이기만 하면 되지 뭐“ • acquire-release “적어도 너랑 나는 순서대로 쓰고 읽자“ • sequentially consistent “꼭 순서대로 읽고 써라 싱글 스레드다~ 생각하고“
  • 103. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 103 Memory Ordering 비용 작음 비용 큼 약함 가장 엄중함 relaxed acquire-release sequentially consistent default
  • 104. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 104 Default Memory Ordering • 가장 비싸지만, 가장 안전한 것이 default • 지금까지 사용한 모든 atomic 연산은 seq_cst
  • 105. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 105 Memory Ordering relaxed acquire-release sequentially consistent
  • 106. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 106 memory_order_seq_cst • sequentially consistent • It requires global synchronization between all threads • 가장 강력한 제약 • 가장 비싼 비용 • 서로 다른 스레드들의 연산을 선형화 가능
  • 107. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_seq_cst 107 listing 5.4 z가 0이 되는 경우가 있는가? t1 t2 t3 t4
  • 108. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_seq_cst 108 스레드 간 선행 관계 t1은 t3보다 선행 t1 t2 t3 t4 t2는 t4보다 선행
  • 109. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_seq_cst 109 가능한 경우의 수 t1 t2 t3 t4 t1 t2 t3 t4 z == 2 t1 t2 t4 t3 z == 2 t1 t3 t2 t4 z == 1 t2 t1 t4 t3 z == 2 t2 t1 t3 t4 z == 2 t2 t4 t1 t3 z == 1
  • 110. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_seq_cst 110 memory_order_seq_cst • 선형화 가능 • 상식에 맞는 행동 • is_lock_free() 가 true일 때에는 lock free • Lock 보다 빠름 결론 : seq_cst 쓰시죠
  • 111. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_seq_cst 111 닝겐의 욕심은 끝이 없고… • “난 그렇게까지 빡빡한 동기화는 필요 없는데“ • “좀 더 빠른 건 없나요?” http://www.ddengle.com/entertainment/635506 왜 없겠어요
  • 112. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_seq_cst 112 하지만 그 대가는 클 것입니다. • seq_cst 가 없는 멀티 스레드 세상에선 그 무엇도 가능합니다 • 아까 보았던 -65535 • 0.05% 의 확률로 크래시 • 모니터 자연 발화 • relaxed ordering 을 통해 체험해봅니다.
  • 113. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 113 Memory Ordering relaxed acquire-release sequentially consistent
  • 114. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 114 Listing 5.5 z는 프로그램이 끝날 때까지 0일 수 있습니다.
  • 115. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 115 Listing 5.5 의 흐름 x.store(true, relaxed) y.store(true, relaxed) y.load(relaxed) return true x.load(relaxed) return false ????
  • 116. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 116 싱글 스레드 입장에서 생각해봅시다 x.store(true, relaxed) y.store(true, relaxed) y.load(relaxed) return true x.load(relaxed) return false
  • 117. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 117 조금 더 복잡한 예제 • Listing 5.6
  • 118. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 118 가능한 결과 중 하나 t1 : (0, 0, 0), (1, 0, 0), (2, 0, 0), (3, 0, 0), (4, 0, 0), (5, 7, 0), (6, 7, 8), (7, 9, 8), (8, 9, 8), (9, 9, 10) t2 : (0, 0, 0), (0, 1, 0), (0, 2, 0), (1, 3, 5), (8, 4, 5), (8, 5, 5), (8, 6, 6), (8, 7, 9), (10, 8, 9), (10, 9, 10) t3 : (0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 0, 4), (0, 0, 5), (0, 0, 6), (0, 0, 7), (0, 0, 8), (0, 0, 9) t4 : (1, 3, 0), (2, 3, 0), (2, 4, 1), (3, 6, 4), (3, 9, 5), (5, 10, 6), (5, 10, 8), (5, 10, 10), (9, 10, 10), (10, 10, 10) t5 : (0, 0, 0), (0, 0, 0), (0, 0, 0), (6, 3, 7), (6, 5, 7), (7, 7, 7), (7, 8, 7), (8, 8, 7), (8, 8, 9), (8, 8, 9)
  • 119. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 119 relaxed order 의 이해 • 책에 나온 설명 5 note
  • 120. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 120 Store 5 10 note 10 저장 좀
  • 121. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 121 Store 5 10 23 3 1 2 42 note 23 저장 좀 3 저장 좀 1 저장 좀 2 저장 좀 42 저장 좀
  • 122. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 122 Load 5 10 23 3 1 2 42 note 23 저장 좀 3 저장 좀 1 저장 좀 2 저장 좀 42 저장 좀 지금 값 뭐? 어떤 수를 알려 줘야 할까? ?
  • 123. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 123 우리의 입장 • 당연히 42 5 10 23 3 1 2 42 note 이거 찾으시죠? ㄳ
  • 124. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 124 큐빅맨의 입장 • note 에 쓰여진 값 중 어떤 값이라도 전달 가능 5 10 23 3 1 2 42 note 뭐가 최신인지 내가 어떻게 알아 걍 주는대로 받아 네 中 1개
  • 125. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 125 Reload 5 10 23 3 1 2 42 note 그럼 지금은 값 뭐임? 한번 더, 어떤 수를 알려 줘야 할까? 또? 이전 값
  • 126. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 126 Reload • 전에 알려줬던 값보다 더 과거의 값을 알려주진 않는다. 5 10 23 3 1 2 42 note 옛날 값 주면 욕 먹겠지?이전 값 中 1개 굳
  • 127. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 127 Listing 5.5 다시 생각해봅시다. x.store(true, relaxed) y.store(true, relaxed) y.load(relaxed) return true x.load(relaxed) return false x y x 와 y는 서로 다른 큐빅맨
  • 128. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 128 memory_order_relaxed • relaxed order 는 순서 제약이 없으므로 빠르다. 하지만 • 비직관적이고, 다루기 어렵다. • 반드시 더 강한 ordering 과 함께 사용해야 한다. “I strongly recommend avoiding relaxed atomic operations unless they’re absolutely necessary” – Anthony Williams
  • 129. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_relaxed 129 대안은 없을까? • seq_cst 보다 빠르면서 • relaxed 보다 쎈 거
  • 130. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 130 Memory Ordering relaxed acquire-release sequentially consistent
  • 131. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 131 Listing 5.7 t1 t2 t4t3 z는 0일 수 있을까? 쓰기용 읽기용
  • 132. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 132 불행히도 relaxed 랑 똑같습니다. t1 t2 t4t3 선행 관계 아님 x == true 여도, y == false 일 수 있음 y == true 여도, x == false 일 수 있음
  • 133. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 133 acquire-release 의 한계 • 서로 다른 스레드에서 write -> 수정 순서를 보지 못한다. • Listing 5.7의 assert가 안뜨게 하려면 seq_cst 를 써야함
  • 134. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 134 그럼 acquire-release 가 해주는 게 뭔가요
  • 135. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 135 Listing 5.8 여기서는 z가 0이 되지 않습니다.
  • 136. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 136 memory_order_acquire / _release • release 로 쓴 변수를 • acquire 로 읽으면 • 쓰기와 읽기가 동기화 • 스레드 간 선행 관계가 성립한다.
  • 137. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 137 Listing 5.8 다시보기 x.store(true, relaxed) y.store(true, release) y.load(acquire) return true x.load(relaxed) return true 선행관계 성립
  • 138. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 138 acquire-release 의 이해 1p 2p 3p note 노트는 사실 여러 페이지
  • 139. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 139 release 의미론으로 쓴다는 의미 x y x 야. 1페이지에 true 저장해줘. false false true y 야. 1페이지에 true 저장해줘. 근데 이게 마지막이야 true true를 쓰고 페이지를 넘김 종이 아깝게
  • 140. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 140 acquire 의미론으로 읽는다는 의미 x y false false true true y 야. 지금 값 뭐니? (뒷돈을 건네며) 이게 이번 페이지 마지막 값이야
  • 141. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 141 acquire 이후의 relaxed 읽기 x y false false true true x 야. 지금 값 뭐니? 다 알고 왔다. 귀찮게 찾아야 하잖아
  • 142. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 142 memory_order_acquire / _release • 항상 최신 값을 주는 게 아님 • y 가 true임을 읽었을 때, 그 위에 있던 x.store(true, relaxed) 가 선행되었음을 보장 • 즉, 순서가 뒤바뀌지 않았음을 보장
  • 143. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 143 acquire-release 의 이행성 • a->b, b->c 이므로 a->c x.store() -> y.store(), y.store() -> y.load(), y.load() -> x.load() 이므로 x.store() -> x.load()
  • 144. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 144 acquire-release 의 이행성 x.store(true, relaxed) y.store(true, release) y.load(acquire) return true x.load(relaxed) return true
  • 145. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_acquire / _release 145 acquire-release 의 이행성 x.store(true, relaxed) y.store(true, release) z.load(acquire) return true x.load(relaxed) return true y.load(acquire) return true z.store(true, release)
  • 146. C++ Concurrency in Action Study C++ Korea Memory Ordering memory_order_consume / _release 146 memory_order_consume • 동기화할 데이터는 하나로 충분할 때 • release로 저장된 변수의 데이터 의존성을 다른 스레드로 전달 • 의존성이 없는 변수는 선행관계 x k = 11; b = 1; e = b+10; a.store(e, release) x = 0; while(x = a.load(consume)); // x == e, b == 1 보장 y = x – 10; x = y + 1; t = k; // 선행관계 아님 저보다 훠어어얼씬 더 잘 설명해준 슬라이드 http://www.slideshare.net/YiHsiuHsu/introduction-to-memory-order-consume
  • 147. C++ Concurrency in Action Study C++ Korea Memory Ordering relaxed and acquire-release 147 relaxed 와 acquire / release 비교 • Listing 5.5 • relaxed 일 때 • acquire-release 일 때 왜 둘 다 에러가 안 나지?
  • 148. C++ Concurrency in Action Study C++ Korea Memory Ordering relaxed and acquire-release 148 relaxed 와 acquire / release 가 차이가 없는 이유 Microsoft : 우리 컴파일러는 volatile 이면 acquire / release 임 ㅋ ISO : … https://msdn.microsoft.com/ko-kr/library/12a04hfd.aspx
  • 149. C++ Concurrency in Action Study C++ Korea Memory Ordering relaxed and acquire-release 149 /volatile:iso 로 바꾸어보자 프로젝트 속성 그런데 이래도 Listing 5.5 는 잘 돕니다.
  • 150. C++ Concurrency in Action Study C++ Korea Memory Ordering relaxed and acquire-release 150 relaxed 와 acquire / release 가 차이가 없는 이유2 Intel : 우린 일반 변수도 acquire / release 임 ㅋ ARM : … ISO : … MS : 헐 ㅋ 굳 ㅋ
  • 151. C++ Concurrency in Action Study C++ Korea Memory Ordering relaxed and acquire-release 151 어떤 차이가 있길래? • Reordering 을 어떻게 하느냐의 차이! • 그런데 Reordering이 무언가요
  • 152. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 152 Reordering 종류 Load Load Load Store Store Load Store Store
  • 153. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 153 아키텍쳐 별 Reordering Load Load Load Store Store Load Store Store x86은 Store Load 일 때에만 reordering ARM은 네 경우 모두 reordering https://en.wikipedia.org/wiki/Memory_ordering
  • 154. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 154 x86-64 에서는? Intel 64-ia-32 architectures software developer system programming manual volume 3 x86-64도 Store Load 일 때에만 reordering
  • 155. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 155 이제 이렇게 부릅시다. 인텔은 Store Load 일 때에만 reordering Strong Memory Models ARM은 네 경우 모두 reordering Weak With Data Dependency Ordering http://preshing.com/20120930/weak-vs-strong-memory-models/
  • 156. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 156 x86 이나 x86-64 아키텍쳐 intel 이나 amd 같은 PC에서 일반적으로 사용하는 cpu는 acquire-release 이하의 의미론을 사용하는 데 추가적인 명령어가 필요 없다. (즉, 일반 변수도 acquire-release) seq_cst 에 약간의 추가적인 store 비용이 들 뿐이다. 하지만 ARM 이나 PowerPC 에서는 차이가 크다. -Anthony Williams 본문에는 이렇게 설명되어 있습니다.
  • 157. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 157 http://www.slideshare.net/YiHsiuHsu/introduction-to-memory-order-consume 차이가 얼마나 큼?
  • 158. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 158 Reordering 이랑 C++ Memory Ordering 이랑 무슨 상관인가요? Load Load Load Store Store Load Store Store memory_order_seq_cst memory_order_release memory_order_acquire memory_order_relaxed
  • 159. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 159 Load Load Load Store Store Load Store Store Reordering 과 C++ Memory Ordering 의 상관관계 x.store(true, relaxed) y.store(true, release) y.load(acquire) return true x.load(relaxed) return true
  • 160. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 160 Load Load Load Store Store Load Store Store Reordering 과 C++ Memory Ordering 의 상관관계 x.store(true, relaxed) y.store(true, release) y.load(acquire) return true x.load(relaxed) return true 낚이지 마세요. 이렇게는 Store Load 고려 대상이 아닙니다. 스레드가 다르니까요.
  • 161. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 161 Load Load Load Store Store Load Store Store Reordering 과 C++ Memory Ordering 의 상관관계 x.store(true, relaxed) y.store(true, release) y.load(acquire) return true x.load(relaxed) return true
  • 162. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 162 Load Load Load Store Store Load Store Store Reordering 과 C++ Memory Ordering 의 상관관계 x.store(true, relaxed) y.store(true, release) z.load(acquire) return true x.load(relaxed) return true y.load(acquire) return true z.store(true, release)
  • 163. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 163 아직 한 발 남았습니다. Store Load x86-64 에서는 Reordering에 의한 버그는 못보나요?
  • 164. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 164 피터슨 알고리즘 http://www.slideshare.net/deview/242-naver2?qid=79a97d1c-4ba8-4c89-bda5-2e1387e6e1e6&v=qf1&b=&from_search=4 http://www.slideshare.net/zzapuno/kgc2013-3?qid=9e511612-d469-47cd-96cd-b6a0a623fd9e&v=qf1&b=&from_search=1
  • 165. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 165 seq_cst 말고는 답이 없는가? • 우리가 reordering 을 막을 방법은 정녕 없는 것인가요?
  • 166. C++ Concurrency in Action Study C++ Korea Memory Ordering reordering 166 memory fence • 위 연산의 결과가 메모리에 모두 쓰여질 때까지 • 다음 명령어를 실행하지 않는다.
  • 167. C++ Concurrency in Action Study C++ Korea Memory Ordering for atomic operation 167 Listing 5.13 • fence를 사용하여 동기화하기 • C++11 : std::atomic_thread_fence() • (주의) ++a 를 mfence 로 감싼다고 아토믹이 되는 것은 아님
  • 168. C++ Concurrency in Action Study C++ Korea Summury 168 결론 • Data Race 를 없애기 위해 atomic<T> 을 사용 • 복잡한 알고리즘에는 Lock을 사용 • 성능 향상을 위해 memory ordering 직접 지정 • CPU 아키텍처 별로 고려해야 할 정도가 다름 • fence를 이용해 reordering을 막을 수 있음
  • 169. C++ Concurrency in Action Study C++ Korea 감사합니다.
  • 170. C++ Concurrency in Action Study C++ Korea Reference 170 http://preshing.com/20120930/weak-vs-strong-memory-models/ http://www.slideshare.net/deview/242-naver2?qid=3b220326-f8fb-4392-9b5f-0efe29d7823c&v=default&b=&from_search=4 http://www.slideshare.net/zzapuno/kgc2013-3?qid=9e511612-d469-47cd-96cd-b6a0a623fd9e&v=qf1&b=&from_search=1 http://www.slideshare.net/YiHsiuHsu/introduction-to-memory-order-consume https://en.wikipedia.org/wiki/Memory_ordering http://en.cppreference.com/w/cpp/atomic/ http://egloos.zum.com/recipes/v/5170809 멀티프로세서 프로그래밍 (The Art of Multiprocessor Programming) – 모리스 헐리히, 니르 샤비트 / 김진욱, 하재승 역 C++ concurrency in action – Anthony Williams Intel 64-ia-32 architectures software developer system programming manual volume 3

Editor's Notes

  • #9: 우리는 이 문장을 다시 한번 생각해 볼 필요가 있습니다.
  • #10: 데이터 레이스가 일어나는 대상은 과연 ‘객체‘ 일까요?
  • #14: 책이 잘못된 걸까요?
  • #18: 데이터 레이스는 같은 “메모리 공간“ 에 접근할 때 발생한다.
  • #22: 굉장히 두려운데요
  • #26: 만약 이렇다면, 당신은 data race 와 미정의 동작을 모두 갖고 있는 것입니다.
  • #27: 예제 코드를 한번 볼까요? (5.1.3 cache line boundary)
  • #29: 하지만 컴파일러에게 알려주는 것도 그렇게 쉽지만은 않습니다.
  • #32: 이 전사는 고블린과 열심히 싸우다가 피가 1 !!! 남았습니다!!!!! 고블린을 쓰러뜨린 직후에, 옆에 있던 회색 도시쥐가 전사를 인식했습니다. 회색 도시쥐의 공격력은 2 !!!라서, 지금 한 대 맞으면 전사는 죽습니다. 이에 파티원 두 명이 급하게 힐링을 써주었습니다. 이 친구들은 본디 법사라서 힐이 1 밖에 안차네요. 그래도 괜찮습니다. 피는 3 !!! 이 되고, 전사는 살 수 있을 것입니다. 그런데 이 전사는 한 대 맞고 죽고 말았다고 합니다. 이 전사는 왜 죽었을까요?
  • #33: “쓰기 전 상태“ 도 아니고 “쓴 후의 상태"도 아닌, 그 둘이 겹쳐진 어떤 값을 리턴하는 상태를 데이터 레이스 라고 하며, 이 상태는 미정의 동작을 유발하게 됩니다. 방금 전 보셨던 비트필드가 예시가 될 수 있겠네요. 전사가 죽었던 이유도 바로 이 데이터 레이스 때문입니다.
  • #34: a의 값을 읽어 eax에 넣고, eax에 1을 더하고, eax를 a에 저장하는 세 개의 명령으로 되어있는 것을 볼 수 있습니다.
  • #35: 만약 두 스레드에서 ++a를 동시에 실행하면 어떻게 될까요? 칠판에 설명해보겠습니다. 이래서 전사는 죽게 되었던 것입니다. + 사실 명령어가 하나라고 원자적인 것은 아닙니다. 설명이 쉽도록 예시를 든 것이므로 오해 없으셨으면 합니다.
  • #36: 원자적 연산은 더 이상 나눌 수 없다고 말씀드렸었죠? 이것이 바로 ++a의 원자적 연산인 InterlockedAdd() 의 내부 구현입니다. 아까보다 더 많은 일을 하는 것처럼 보이겠지만, 사실은 “읽고, 수정하고, 쓰기” 과정이 하나의 명령어로 처리되는 것을 보실 수 있습니다. ecx 에 읽는 것은, a의 초기값이 아니라 a의 주소값입니다.
  • #37: 이런 것들을 연산자 오버로딩 해놓은 클래스가 있으면 좋겠다고 생각한 사람이 있었고 이것이 C++표준이 되었습니다. 그것이 바로 C++ 11 에서 추가된 atomic type 입니다.
  • #45: 그럼 이 때 atomic으로 선언한 변수 a로 exchange() 멤버함수를 호출하는 건 원자적이지 않은 것일까요? 그건 당연히 아니겠죠? 그냥 단지 락 프리가 아닐 뿐입니다. 락 프리가 아닌데 원자적이라면, 당연히 ~ 락을 쓰는 것이겠지요.
  • #47: 어떤 원자적인 플래그로, _Lock_spin_lock() 을 호출하여 락을 건 후, memcpy() 를 하고 있네요. _Lock_spin_lock() 함수를 좀 더 자세히 볼까요?
  • #48: 바쁜대기네요. 플래그가 세팅되어 있는지 확인하고, 다른 스레드에게 선점권을 넘겨주는 방식으로 구현되어 있습니다. 그리고 이 선점권을 넘기는 코드는 당연히 …
  • #49: 시스템 콜일 줄 알았는데 아니네요.
  • #50: 하지만 너무 큰 사이즈의 클래스는 atomic에는 맞지 않다는 걸 알 수 있습니다.
  • #51: 잠깐 딴 길로 샌 것 같았지만 어쨌든, 우리는 계속 atomic 타입에 대해 이야기하고 있습니다.
  • #53: 아까 T타입에 따라 다른 연산을 제공한다고 했었죠? 정확히는, 이렇게 분류할 수 있겠네요. 이제부터 각 타입에 따라 제공하는 연산에 대해 알아보겠습니다.
  • #55: memory order 는 나중에 다시 설명드리겠습니다. atomic 타입의 거의 모든 연산에는 이렇게 ordering을 지정할 수 있다는 것만 기억해주세요.
  • #61: 일반 bool 로부터 초기화가 가능하다는 것은, true 로도 false 로도 초기화할 수 있다는 것을 의미합니다.
  • #67: 정확히에 대한 뉘앙스도 역시 뒤에서 알아보겠습니다.
  • #69: 일반 bool 로부터 초기화가 가능하다는 것은, true 로도 false 로도 초기화할 수 있다는 것을 의미합니다.
  • #70: 일반 bool 로부터 초기화가 가능하다는 것은, true 로도 false 로도 초기화할 수 있다는 것을 의미합니다.
  • #72: 일반 bool 로부터 초기화가 가능하다는 것은, true 로도 false 로도 초기화할 수 있다는 것을 의미합니다.
  • #74: UDT 제약 조건은 생각보다 많습니다. 이게 무엇을 의미할까요?
  • #86: 사실 이것은 동기화라고 볼 수도 있습니다.
  • #90: thread 2 가 읽는 값 초기값인 0을 읽거나 thread 1 이 쓴 10을 읽거나
  • #106: 디폴트부터 순서대로 한번 봐볼까요?
  • #108: listing 5.4 이 네개의 함수를 모두 각기 다른 스레드로 돌렸을 때, z가 0이 되는 경우가 있을까요? 코드를 보면서 한번 생각해보죠
  • #110: t1 -> t3 t2 -> t4 라는 순서가 정해져 있으니 가능한 경우의 수는 위와 같습니다. 맨 처음에 t1이 실행되었는데, 바로 뒤에 t4가 실행되는 건 있을 수 없는 일입니다.
  • #112: 하지만 c++ 커미티들은 이 것으로 우리가 만족하지 않을 것이란 걸 알고 있었어요. 좀 더 빠른 게(클릭) 왜 없겠어요 당연히 있죠
  • #115: 코드는 조금 있다가 acquire release 까지 훑고 나서 비교하면서 돌려보도록 하죠
  • #116: 이 예제에서, z가 0이 나온다는 것은 위와 같은 상황이 발생한다는 뜻입니다.
  • #117: 싱글 스레드 입장에서 생각해보면 x를 먼저 store 하든, y를 먼저 store 하든 상관이 없습니다. x와 y는 서로 의존성이 없으니까요. load 도 마찬가지입니다.
  • #119: 이 결과를 자세히 보시면 x를 업데이트 하는 t1 스레드에서, x = 5를 쓸 때 이미 y 가 7인 것을 보았습니다. 그런데 y를 업데이트하는 t2스레드에서는, y = 4를 쓸 때 x가 이미 8인 것을 보았습니다. 마치 미래를 관측한 듯한 결과를 볼 수 있습니다. 자세한 실행 순서는 저도 알 수가 없습니다. 순서바뀜으로 인해 이러한 결과가 나올 수도 있다는 것만 기억해주시면 될 것 같습니다. 시간이 된다면 여기서 어떻게 실행되면 이렇게 되는지 토의해보았으면 좋겠습니다.
  • #120: 정육면체의 방 안에 들어있는 사람에게 전화 이 사람은 노트를 들고 있음 노트는 처음에 5가 쓰여있음 눈치채셨겠지만 이건 메모리임.
  • #121: relaxed order 의 이해 어떤 사람(1) 이 큐빅맨에게 전화 “10을 저장해주세요“ 노트에는 10이 쓰여짐.
  • #122: relaxed order 의 이해 어떤 사람(1) 이 큐빅맨에게 전화 “23, 3, 1, 2, 42를 저장해주세요“ 노트에는 23, 3, 1, 2, 42가 쓰여짐
  • #123: relaxed order 의 이해 어떤 사람(2) 가 큐빅맨에게 전화 “저장된 수를 알려주세요” 어떤 수를 리턴할까?
  • #124: relaxed order 의 이해 어떤 사람(2) 가 큐빅맨에게 전화 “저장된 수를 알려주세요” 어떤 수를 리턴할까?
  • #125: relaxed order 의 이해 어떤 사람(2) 가 큐빅맨에게 전화 “저장된 수를 알려주세요” 어떤 수를 리턴할까?
  • #126: relaxed order 의 이해 어떤 사람(2) 가 큐빅맨에게 전화 “저장된 수를 한번 더 알려주세요” 이 때에는, 이전에 알려줬던 값 or 그보다 나중 값을 알려줌 이전에 알려줬던 값보다 과거의 값을 말해주지는 않는다
  • #127: relaxed order 의 이해 어떤 사람(2) 가 큐빅맨에게 전화 “저장된 수를 한번 더 알려주세요” 이 때에는, 이전에 알려줬던 값 or 그보다 나중 값을 알려줌 이전에 알려줬던 값보다 과거의 값을 말해주지는 않는다
  • #128: 이 예시를 List5.5 에 적용해서 다시 한번 생각해보죠. 왜 x에서 false를 읽을 수 있었던 것일까요? x의 값을 물어봤을 때, x의 최신 값을 알려줄 필요는 없다. x와 y는 다른 큐빅맨이므로
  • #130: 왜 없겠어요
  • #132: acquire release 의 한계부터 보고 가시죠. 이 때 z는 0이 될 수 있을까요? 당연히 x랑 y를 제대로 읽어서 z 0이 안되게 하려고 쓰는 거겠죠? 그런데 결론부터 말하자면 0이 될 수 있습니다. (vs + intel 에서는 z == 0 안됨)
  • #136: acquire release 의 역할 드디어 이 z는 0이 되지 않습니다. (오예) 이것이 바로 acquire-release 의 용도입니다.
  • #137: t1 에서 release 로 쓴 변수를 t2 에서 acquire 로 읽으면 쓰기와 읽기가 동기화되며, 스레드 간 선행 관계가 성립한다.
  • #138: t1이 y를 release 로 쓰고, t2가 y를 acquire 로 읽으면 x까지 seq_cst 처럼 선행관계가 성립하게 되는 것입니다.
  • #139: 큐빅맨이 들고있던 노트는 사실 한 페이지가 아니었습니다. 그리고 사실 스레드들이 값을 저장할 때에는 “1페이지에 10 저장해줘” 라고 페이지까지 지정해줌
  • #140: t1 이 x 큐빅맨에게 “1페이지에 true”를 저장하고 이어서 y 큐빅맨에게 “1페이지에 true”를 저장하는데, 이 때 y에게는 “이게 이번 장 마지막 값이야“ 라고 알려줌
  • #141: t2가 y 큐빅맨에게 현재 값을 물어봄. true 를 알려줄 때까지 루프를 몇 번 돌다가, 결국 y가 true 값을 넘겨줌. 그런데 y 큐빅맨이 t2 에게 true 값을 주면서 이렇게 말함 “이 값이 1페이지 마지막 값이야“
  • #142: t2는 이제 호구가 아님. x 큐빅맨에게 가서 “다 알고 왔으니까 빨리 1페이지 마지막 값 내놔라“ 라고 말함. x는 울며 겨자 먹기로 1페이지를 찾아서, 마지막 값인 true를 넘겨줌
  • #144: acquire release 를 사용하여 얻은 스레드 간 선행관계는 이행적입니다. 즉 A->B 이고 B->C 이니까 A->C인거죠. 사실 이행적임을 보장하기 때문에 스레드 간 선행관계가 성립된다고 보아도 되겠죠?
  • #145: 그림으로 그려보면 이와 같습니다.
  • #146: 스레드가 몇 개이든 상관 없이, 이행성은 성립합니다.
  • #148: Listing 5.5 직접 VS로 돌려보기 relaxed 일 때 release 일 때 둘 다 에러 안 남. 왜 에러가 안 나지?
  • #153: 서로 데이터 의존성이 없는 두 변수에 대해서 순서를 바꿀 것인가 말 것인가가 바로 Reordering 입니다. Load Load 는 (클릭) 어떤 변수를 읽고, 다시 다른 변수를 읽을 때 이 순서를 바꿀 것인가 말 것인가를 뜻합니다. 만약 Load Load reordering 을 한다! 라고 하면 이 x와 y의 순서를 바꿔서 읽을 수 있는 것이죠.. (쭉 설명) 싱글 스레드 입장에서 보면, 이 네개의 reordering 은 모두 프로그램 결과에 영향을 미치지 않습니다. 데이터 의존성이 없기 때문이죠. 하지만 멀티스레드에서는 이게 문제가 되기 때문에 cpu 아키텍쳐별로 어떤 reordering 을 지원할 것인가가 다릅니다.
  • #154: Wiki에 이렇게 정리가 되어있는데요. 보시면, x86은 Store Load reorderin만을, ARM은 네 경우 모두 reordering을 하는 것을 볼 수 있습니다.
  • #155: 그럼 요새 나오는 x86-64 는 어떨까요? 인텔 매뉴얼 볼륨 3에 8.2.2 절을 보시면 P6 아키텍처 이후에는 모두 Store Load 만 reordering 한다고 하네요 진짜인지 알아보기 위해 시간이 되면 visual studio atomic 라이브러리를 까서 내부를 확인합니다.
  • #156: 여기는 intel 이라고만 해놓았지만, 같은 x86-64구조를 사용하는 amd 도 마찬가지입니다. 그리고 또 하나, arm 이 Weak Memory Model 이 아닌 이유는, arm은 데이터 의존성이라도 지켜주기 때문입니다. 그것마저 안지켜주는 아키텍처도 있다고 하네요. 알파 라고..
  • #160: x 쓰기와 y 쓰기의 순서가 뒤바뀌면, 마지막에 x.load()가 true 를 읽을 수 있을까요?
  • #161: 이건 store load reordering 과는 관계가 없습니다. 아마 기억하고 계시겠지만, y.load()는 while문을 돌면서 y에서 true를 읽을 때까지 루프를 돕니다. 애초에 이 둘은 다른 스레드에 있는 애들이라, 순서를 정의할 수가 없습니다.
  • #162: y 읽기와 x 읽기의 순서가 뒤바뀌면, 마지막에 x.load()가 true 를 읽을 수 있을까요? 아직 Load Store 가 남았지요? 인텔은 Load Store reordering 도 막아주어서 acquire-release가 정상적으로 동작하는 것인데요 Load Store는 왜때문에 막은 것일까요?
  • #163: 바로 이행성을 보장하기 위해 Load Store reordering을 막은 것입니다.
  • #164: 그럼 Store Load 를 지원하지 않으면 일어나는 일은?
  • #165: 코드 참고
  • #166: seq_cst 말고는 답이 없는가? 우리가 seq_cst를 구현할 방법이 없는가?