-
멀티 스레드 프로그래밍의 문제 : 데이터 오염분석과탐구 2021. 5. 20. 14:23
문제상황
서버로부터 설정(폴리시)이나 플래그 값을 받아오는 스레드(폴리시 스레드)가 있고, 이 값을 바탕으로 작업을 하는 스레드(워킹 스레드)가 있다. 폴리시 스레드에서 기존의 폴리시를 업데이트 할 것이고, 워킹 스레드에서 윗 줄의 코드에서는 이전 폴리시를 사용했는데 아랫 줄의 코드에서는 최신의 폴리시를 써서 생기는 데이터 오염을 해결하고 싶어한다. 작성자는 그 해결 방안으로 글로벌 변수로 되어있는 폴리시를 스레드 내에서 지역변수로 복사하고, 이 지역변수를 폴리시로 인식하고 작업을 풀어갔다.
해결방법
질문자의 해결법도 괜찮은 것 같은데, 하나 문제가 있다. 글로벌 변수에서 지역변수로 복사할 때, 명시적인 락이 없다면, 복사하는 과정에서도 데이터가 오염될 수 있다. 복사라는 게 결국 4바이트나 8바이트 혹은 바이트 단위로 src->dest로 데이터를 채워넣는거니까... 복사 초반의 데이터가 이전 폴리시, 복사 끝물의 데이터가 최신 폴리시 일 수 있다.
Consistency를 지키면서 속도를 업그레이드 하고 싶은 상황이라고 본다. 락을 안쓰고 해결할 수도 있고, 락을 써서 해결할 수도 있다.
락을 안쓰는 해결방법은 폴리시 변수(구조체,클래스 등)를 두 개 들고 다니는 것이다. A, B 폴리시를 들고 있고, 폴리시 스레드에서 업데이트할 때, A 한 번, B 한 번... 번갈아가면서 업데이트한다. 그리고 최신의 폴리시가 어떤 것인지 가리킬 변수를 업데이트한다. 워킹스레드에서는 이 변수를 보고 어떤 폴리시를 사용할지 선택한다.
이 방식의 문제점은 ABA문제랑 비슷하다. A 폴리시를 업데이트하고, 워킹스레드에서 A폴리시를 가지고 작업을 하는데, 마침 서버에서 업데이트를 두 번하여 B, 그리고 다시 A를 업데이트하여 워킹스레드에서 오염된 A폴리시를 가지고 작업할 가능성이 있다. 간단한 해결책은 폴리시 배열을 만들어서 index로 여유있게 사용하면 된다.
락을 쓴다면 간단히 해결된다. 워킹스레드에서는 폴리시를 읽기만 할테니 SRWLock의 shared 모드로 read만하고, 폴리시 스레드에서는 SRWLock의 exclusive모드를 이용해서 쓴다. 폴리시가 바뀌지 않는 경우에, SRWLock의 함수 호출이 부담될 수 있다. 그런데, SRWLock의 연산은 무척 가벼운 편에 속하므로 딥카피보다 훨씬 나을 것이다. 폴리시가 바뀌는 경우에 워킹스레드 대부분이 wait상태로 변하는 점은 생각해야한다. SRWLock의 단점은 너무나 가벼워서 같은 스레드에서 재귀적으로 락을 쓰면 데드락에 빠지는건데, 이 경우엔 그럴일도 없다.
'분석과탐구' 카테고리의 다른 글
CRTP는 어떻게 가능할까? (0) 2021.10.13 캐시 친화적인 코드를 찾으려 했으나 실패... (0) 2021.10.12 OverlappedIO에서 소켓 버퍼 사이즈를 바꾸는 것은 대부분 성능에 영향이 없다. (1) 2021.06.05 소켓의 수신 버퍼 크기를 0으로 할 때 주의할 점. (4) 2021.05.30 switch-case optimization (0) 2021.05.23