일 수 있는 상황이 연출되는 것은 대입 문에 대한 원자성이 보장되지 않기 때문이다.. 군요.
단, 조건은 대입중간에 쓰레드 문맥 전환이 일어나야하므로, kernel thread 이어야할 것 같은데요.
우선 Kernel thread일 필요는 없습니다.
오히려 Kernel thread는 원자적 보장이 더 쉽게 됩니다. (CPU한개일때)
원자적 보장의 한계인 원자단위 즉, 32bit이상의 크기를 다룰때
발생하는 총체적인 경쟁조건을 예로 들기 위한 단편적인 부분입니다.
여기서는 unsigned long long 을 예로 들어서 64비트를 예로 한것이지만
실제 실무에서는 이것이 구조체가 많을겁니다.
제가 설명하고픈 것은 바로 그것입니다.
unsigned long long에 대입하는 부분을 역 어셈블 해보세요.
그러면 그 원인이 쉽게 이해가실거라 사료됩니다.
우선 Kernel thread일 필요는 없습니다.
오히려 Kernel thread는 원자적 보장이 더 쉽게 됩니다. (CPU한개일때)
원자적 보장의 한계인 원자단위 즉, 32bit이상의 크기를 다룰때
발생하는 총체적인 경쟁조건을 예로 들기 위한 단편적인 부분입니다.
여기서는 unsigned long long 을 예로 들어서 64비트를 예로 한것이지만
실제 실무에서는 이것이 구조체가 많을겁니다.
제가 설명하고픈 것은 바로 그것입니다.
Kernel thread가 원자적 보장이 더 쉽게 된다는 건 어떤 근거인가요?
잘 이해가 안 가네요?
그리고, 워드 단위(예를 들어 32bit)의 크기를 다룬다고 해서 원자성이 보장된다는 것은 항상 옳은 것은 아닙니다.
임의의 주소(4의 배수가 아닌)로의 접근이 가능한 플랫폼의 경우(머신 자체에서 지원 or OS의 트랩 기능을 이용한 지원)는 실제로는 32bit의 자료형일지라도 워드의 경계에 걸쳐 있을 가능성이 있죠..
그런 경우라면 실제로 메모리 읽기는 두 번이 필요합니다. 즉, 그 사이에 쓰레드가 선점되고 다른 쓰레드가 동일 메모리 주소를 접근할 가능성이 있죠..
물론 위에서 제시하신 경우보다 확률은 더더욱 희박합니다.
단, 조건은 대입중간에 쓰레드 문맥 전환이 일어나야하므로, kernel thread 이어야할 것 같은데요.
minzkn wrote:
우선 Kernel thread는 비선점형 이라는 점을 예기하겠습니다.
^^ 저의 질문이 모호하게 해석되어서 그런 것 같습니다.
저는 pthread 구현이 kernel thread 를 기반으로 구현되어야한다고 생각했던 것이고, 만일 user thread 라면 오히려 중간에 context switching이 안될 것이다라는 생각으로 말한 것이었습니다.
즉, pthread가 kernel thread 기반일 경우 사용자의 thread context가 커널의 선점된 스케쥴을 따르기 때문에 위와 같은 상황이 잘 연출 될 것이라는 말을 한 것이었습니다.
minzkn 님께서는 "kernel thread 내부에서"로 해석하여 답하신 것 같네요.
저도 shkwon81님과 비슷한 질문을 하려고 했는데..
둘다 비선점상황에서는 원자성이 대체로 선점상황보다 더 보장된다는 생각으로 의견을 교환한 것 같습니다. :)
이렇게 바꿉니다: InterlockedCompareExchange8Bytes(&s_qword, 0xffffffffllu, 0xffffffff00000000llu);
Destination 위치에 있는 64비트 값을 Comperand와 비교하여 같으면 Exchange를, 다르면 Comperand를 Destination에 대입합니다.
단, 실제로 돌려보지 않고 생각나는대로 짠 것이니 동작이 될지 안될지는 모르겠습니다. 8)
좋은 예제군요.8 byte 의 unsigned long long
좋은 예제군요.
8 byte 의 unsigned long long type에
두 값을 번갈아 써넣을 뿐인데..
일 수 있는 상황이 연출되는 것은 대입 문에 대한 원자성이 보장되지 않기 때문이다.. 군요.
단, 조건은 대입중간에 쓰레드 문맥 전환이 일어나야하므로, kernel thread 이어야할 것 같은데요.
---
http://coolengineer.com
[quote="pynoos"]좋은 예제군요.8 byte 의 uns
우선 Kernel thread일 필요는 없습니다.
오히려 Kernel thread는 원자적 보장이 더 쉽게 됩니다. (CPU한개일때)
원자적 보장의 한계인 원자단위 즉, 32bit이상의 크기를 다룰때
발생하는 총체적인 경쟁조건을 예로 들기 위한 단편적인 부분입니다.
여기서는 unsigned long long 을 예로 들어서 64비트를 예로 한것이지만
실제 실무에서는 이것이 구조체가 많을겁니다.
제가 설명하고픈 것은 바로 그것입니다.
unsigned long long에 대입하는 부분을 역 어셈블 해보세요.
그러면 그 원인이 쉽게 이해가실거라 사료됩니다.
[quote]우선 Kernel thread일 필요는 없습니다. 오히려
Kernel thread가 원자적 보장이 더 쉽게 된다는 건 어떤 근거인가요?
잘 이해가 안 가네요?
그리고, 워드 단위(예를 들어 32bit)의 크기를 다룬다고 해서 원자성이 보장된다는 것은 항상 옳은 것은 아닙니다.
임의의 주소(4의 배수가 아닌)로의 접근이 가능한 플랫폼의 경우(머신 자체에서 지원 or OS의 트랩 기능을 이용한 지원)는 실제로는 32bit의 자료형일지라도 워드의 경계에 걸쳐 있을 가능성이 있죠..
그런 경우라면 실제로 메모리 읽기는 두 번이 필요합니다. 즉, 그 사이에 쓰레드가 선점되고 다른 쓰레드가 동일 메모리 주소를 접근할 가능성이 있죠..
물론 위에서 제시하신 경우보다 확률은 더더욱 희박합니다.
그렇군요!
main의 do while 루프안의 대입 부분을 역어셈 하면 대략 다음과
같이 표현 할 수 있겠군요.
s_qword = 0xffffffffllu;
s_qword = 0xffffffff00000000llu;
두개의 mov 명령으로 실행된다는게 문제인것 같습니다.
movl 한개만 실행되었을때 쓰레드에서 if 문을 실행시킨다면
바로 종료 되는군요. minzkn님께서 말씀해주셨다 시피 실제 구조체
등에서 이런 상황이 발생할 수 있을 것 같습니다.
그렇다면 이를 막을 수 있는 방법은 뭐가 있을까요.
삭제합니다. 더이상 글 안올리겠습니다.
삭제합니다. 더이상 글 안올리겠습니다.
[quote="pynoos"]단, 조건은 대입중간에 쓰레드 문맥 전환이
^^ 저의 질문이 모호하게 해석되어서 그런 것 같습니다.
저는 pthread 구현이 kernel thread 를 기반으로 구현되어야한다고 생각했던 것이고, 만일 user thread 라면 오히려 중간에 context switching이 안될 것이다라는 생각으로 말한 것이었습니다.
즉, pthread가 kernel thread 기반일 경우 사용자의 thread context가 커널의 선점된 스케쥴을 따르기 때문에 위와 같은 상황이 잘 연출 될 것이라는 말을 한 것이었습니다.
minzkn 님께서는 "kernel thread 내부에서"로 해석하여 답하신 것 같네요.
저도 shkwon81님과 비슷한 질문을 하려고 했는데..
둘다 비선점상황에서는 원자성이 대체로 선점상황보다 더 보장된다는 생각으로 의견을 교환한 것 같습니다. :)
---
http://coolengineer.com
간단하게 수정하면 될것 같은데요...음... 하루 정도 돌려보기는
간단하게 수정하면 될것 같은데요...
음... 하루 정도 돌려보기는 힘들것 같네요.. -_-;;;
x86이라면 cmpxchg8b를 써서 다음과 같이 하는 건 어떨까요?
x86이라면 cmpxchg8b를 써서 다음과 같이 하는 건 어떨까요?
즉 다음과 같이 된 것을
이렇게 바꿉니다:
InterlockedCompareExchange8Bytes(&s_qword, 0xffffffffllu, 0xffffffff00000000llu);
Destination 위치에 있는 64비트 값을 Comperand와 비교하여 같으면 Exchange를, 다르면 Comperand를 Destination에 대입합니다.
단, 실제로 돌려보지 않고 생각나는대로 짠 것이니 동작이 될지 안될지는 모르겠습니다. 8)
삭제합니다. 더이상 글 안올리겠습니다.
삭제합니다. 더이상 글 안올리겠습니다.
cmpxchg8b는 %edx:%eax 값을 피연산자가 가리키는 메모리상의
cmpxchg8b는 %edx:%eax 값을 피연산자가 가리키는 메모리상의 64비트 값과 비교해서 같으면 그곳에 %ecx:%ebx 값을 저장하고(ZF=1), 다르면 거꾸로 메모리에 있던 값을 %edx:%eax에 저장합니다(ZF=0).
펜티엄에서 버그가 있다는 얘기는 사실인지 아닌지 잘 모르겠습니다. 언제 도입된 명령어인지도 기억이 확실치 않아서... 8)
댓글 달기