내가 C/C++ 문장을 썼을 때 이게 어셈블리 명령어로 어떻게 바뀌는지 알면
이 문장이 atomic한지 아닌지 금방 깨달을 수 있거든~
- 어셈블리 명령어 하나로 표현되고
- 메모리 액세스가 한번 뿐이어야
그 문장이 atomic한 거임.
내가 C/C++ 문장을 썼을 때 이게 어셈블리 명령어로 어떻게 바뀌는지 알면
이 문장이 atomic한지 아닌지 금방 깨달을 수 있거든~
- 어셈블리 명령어 하나로 표현되고
- 메모리 액세스가 한번 뿐이어야
그 문장이 atomic한 거임.
어셈블리 명령 하나도 실제로 CPU 내부에서 여러 개의 연산으로 나뉘는 경우도 있다는거 아시나용?..
컴파일러 최적화 쪽도 알아야 되는거 아닌가요,, 릴리즈 빌드하면 생각했던 변환하고 생뚱맞은 경우가 적지 않던데
http://en.cppreference.com/w/c/language/atomic
우리가 보는 어셈코드를 CPU가 순서대로 실행하지 않는다는거 아시나요? 로우언어충이네 이거^^
그러면 기계어도 배우자!
이거 바보들이네. micro operation이 atomicity에서 왜 튀어나와 =_=
소프트웨어 통채로 회로로 설계하면 빠를듯
우리가 atomicity를 따지는 이유는 멀티 스레딩 시의 안전성을 확보하기 위함인데, 그 기준은 태스크 스위칭과 멀티 프로세싱에서 안전한가임. 어셈블리 명령어로 하나면 태스크 스위칭을 위한 타이머 인터럽트는 반드시 그 수행 전이나 이후에 일어남이 보장되고, 메모리 액세스가 하나라면 micro-op건 지랄이건 멀티 프로세싱에서 안전하다.
후자의 상황에서 레지스터는 프로세서마다 레지스터 파일이 다르니깐 레지스터를 따지고 자시고 할 건 없지.
제성해여 지엽적인걸로 트집잡아보고 싶었어여ㅠㅠ..
음냐 single instruction 이 atomic 을 보장하진 않음. add eax, [si] 같은 연산을 한다면 특정 하드웨어 조합에서 racing condition 일 발생해.
이 발생해.
single instruction이라고 해서 모두 atomic이 아닌 건 맞는데(제가 글에서 적었듯이 single instruction + single memory access가 조건), add eax, [esi]는 memory access도 한 번 뿐인데 어떻게 발생하죠? read 시점에 다른 프로세서가 write한 상태다, 아니다의 두 가지 경우만 있지, reading하는 도중에 다른 프로세서가 끼어들 수도 있나요?
코세 성님 말씀은, 몇 비트는 다른 프로세서에 의해 alter된 값으로, 몇 비트는 original 값으로 read할 수도 있다는 말씀이신 건가요?
근데 아시다시피 memory access는 word 단위로 발생하잖아요? 차라리 non word unit이라면 모르겠는데요(그건 메모리 접근을 두 번 하니깐.)
memory access는 serial이 아니고 parallel인데, 그게 가능한가요?
쓰기 이야기 아닐까 뭐 이런거 interlocked add 계열
000000013F3824B4 mov eax,1 000000013F3824B9 xor ecx,ecx 000000013F3824BB lock xadd dword ptr [rcx],eax
아 몰랑
add [memory pointer], something 은 메모리 액세스를 두 번 하니깐 multiprocessor에서의 atomicity를 보장하기 위해서는 lock prefix가 필요하지(single processor에서는 atomicity가 보장됨). 근데 코세 성님은 그 얘길 하는 게 아닌 듯. 나도 내 글에 분명히 메모리 액세스가 한번 뿐이어야 한다고 밝혔음~
eax 에 더해지기 전에 esi 의 내용이 바뀌는 수가 있다는거지.
[esi] 가 바뀐다든지.
저거 뿐 아니라 mov byte ptr [xxx], xxx 이런 것도 atomicity가 보장되지 않는다. 왜냐하면 [xxx]에서 4바이트 값을 읽어서(64비트 워드면 8바이트) 거기서 1바이트만 수정해서 다시 write하거든. 메모리 액세스가 두 번 일어남.
codesafer // processor마다 register file이 다른데 어떻게요?
[esi]가 바뀐다는 건 쉽게 이해가 안되네요. memory I/O는 serial이 아니라 parallel이잖아요?
interprocessor parallelism 때문에
esi가 바뀐다는 건 절대 일어날 수가 없는 경우인데요. OS가 제대로 만들어졌다면.
특정 하드웨어 조합. 그러니까 [esi] 가 영향을 받는 경우는, 하이퍼스레딩에선 힘들겠지만 실제 병렬 CPU + 캐시 조합인경우.
esi 에 stall 을 걸어주는건 OS 가 아니라 CPU 내부 구현 문젠데,
interprocessor parallelism 때문에 한 프로세서가 read 작업 수행 도중에 다른 프로세서가 해당 메모리 칩에 write request를 내릴 수 있다는 말씀이신 건가요? 그래서 일부 비트는 변경된 상태로, 일부 비트는 오리지널 값으로 받아오고요? (모든 비트가 다 바뀌었거나, 다 안 바뀌었다면 상관 없죠~)
stall 이 발생하는 경우, 다른 명령이 끼어들 수 있어. 다른 프로세스에선 말야.
직접적으로 eax 나 esi 와 관련되지 않은 명령이 처리되어 버리면
결과적으로 atomic 해 보이지 않을 수 있다는게 첫번째 이슈고
[esi] 의 경우는 실제 꽤 자주 바껴서 문제를 일으킴.
stall이라는 건 pipelining 때문에 말씀이신 건가요?
atomicity와 캐시 불일치 문제는 다른 문제 같은데요 ㄷㄷ
응, esi 에 누군가 쓰고 있다면, stall 이 생겨서 버블을 채울거잖아?
그러면 실제론 1개의 명령처럼 보이는데 그 사이 버블이 쭉 깔리면서 다른명령들이 수행되게 됨.
(다른 프로세스에서)
그래서 atomic 하지 않게 보이는 경우가 있지. 연산자체엔 문제가 없어.
캐시 불일치야 어쨌든 읽어오는 값은 write 되기 전의 값이니 atomic하다고 볼 수 있는 거 아닌가요? 이런 경우만 아니면 되죠. int i = 1; 프로세서 1: print(i); 프로세서 2: i = 0xFFFFFFFF; => 프린트 되는 값: 0xFFFF0001
[esi] 의 경우는 연산자체에 문제를 일으킬 소지가 큰데, 완전히 게런티하기는 쉽지 않은 OS 레벨에서 어케 해줄수 있는건 아님.
race condition이 아니라 캐시 불일치 문제군요 :)
코세 성님. stall이 걸리는데 다른 프로세스의 명령이 수행되는 게 이해가 안되는데요? 태스크 스위칭은 타이머 인터럽트에 의해 발생하잖아요?
다른 프로세서에서 다른 프로세스가 도는 거라면 애초에 같은 esi라도 전혀 다른 레지스터일텐데요?
[esi] 의 경우는 주소 지정의 비유일에 의해서 다른 레지스터여도 상관없는거잖아.
esi 레지스터의 값은 그 어떤 경우에도 절대 안 바뀔 거 같은데.
[esi]가 바뀌는 거 말고 esi 가 바뀌는 경우를 말씀드린 거예요.
[esi]의 경우는, race condition이 아니라 캐시 불일치 문제고요. 즉, atomicity엔 아무 문제 없죠 :)
그러니까, 하이퍼쓰레딩에서는, 단일 로직블럭을 공유하잖아?
넹
eax 와 esi 자체는 interlock 이 걸리더라도 로직 블럭 자체는 다른 넘들이 지나다니니까, 한방에 실행되지 않는것 처럼 보일 수 있다는거
집 가서 읽을게유~ 퇴근 시간임.
ㅇㅇ~
그리고 캐시 불일치 만으로 논할 문제가 아냐. 그냥 메모리 억세스임. 첨엔 캐시고 뭐고 없으니까.
캐시 불일치는 걍 나보다 걔가 더 빨리 실행된 개념으로 받아들이면 atomic한 게 맞고 --- non-atomic은 연산 도중 다른 연산이 연산의 결과를 바꿀 수 있는 걸 의미해요 --- stall은 좀 늦게 실행될 뿐, 그렇다 쳐도 연산의 결과를 바꾸지는 못하니 atomic이죠 :) 지구가 폭발해도 연산 도중에 끼어들어 결과를 못 바꾼다면 atomic~