2016-08-27 3 views
1

lock-free 큐를 사용하여 다중 스레드 안전 로그 작성기를 작성하고 싶습니다. 로깅 쓰레드는 메시지를 대기열로 보내고 로거는 메시지를 보내서 출력으로 보냅니다. 그 문제를 해결하는 방법을 생각해 봅시다. 가능한 한 mutex/locks 사용을 피하고 싶습니다. 그래서 C++ 스트림을 사용하여 파일/console에 기록한다고 가정 해 보겠습니다. 목표 시스템이 Linux라고 가정 할 수 있습니다.원자 시스템 호출. 입력/출력 작업

스트림 작성은 Unix write이 제공하는 시스템 호출 용 래퍼 (고급 래퍼 일 수 있음) 여야합니다. 내가 아는 바로는 syscalls은 원자 적입니다 (단 하나의 프로세스 만이 동시에 syscall을 실행할 수 있습니다). 따라서 파일을 안전하게 작성하기 위해 잠금 장치를 사용하지 않으려 고합니다. 그러나 write은 시스템 호출이지만 "전체 출력"을 작성하는 것은 아닙니다. 파일에 성공적으로 기록 된 바이트 수를 반환합니다.

기본적으로 내 질문은 : 어떻게 해결할 수 있습니까? 뮤텍스를 피할 수 있습니까? (나는 그것이 불가능하다고 생각한다). 내 생각을 표기 해주세요. 내가 틀렸어?

+0

나는 본질을 잘 이해하고 있는지 잘 모르겠다. 문제. 당신이 누구와 경쟁하고 있다고 생각합니까? "상호"배제는 자원을 공유하려는 최소한 두 당사자의 존재를 전제로합니다 - 귀하가 우려하는이 두 번째 당사자는 누구입니까? –

+0

스트리밍하기 위해 경쟁하는 두 개의 스레드가 있습니다. – Gilgamesz

+0

글쎄, 하나의 스레드 만 실제로 I/O를 수행한다는 명백한 목적을위한 큐가있는이 정교한 설정이 있습니다. 그렇다면 왜 당신은 같은 파일에 쓰는 쓰레드를 더 많이 도입하여 자신의 디자인을 방해합니까? 대기열을 사용하는 데있어 중요한 점은 무엇입니까? 그러면 파일을 쓸 수있는 모든 것을 자유롭게 쓸 수 있다면 어떨까요? –

답변

2

이고르가 맞습니다. 단지 하나의 스레드가 모든 로그 기록을 수행하도록하십시오. 커널은 파일 위치를 추적하는 열린 파일 설명자에 대한 액세스를 동기화하기 위해 잠금을 수행해야하므로 여러 코어에서 쓰기를 수행하면 커널 내부에서 충돌이 발생합니다. 더 나쁜 것은 여러 개의 코어에서 시스템 호출을하는 것입니다. 즉, 커널의 코드/데이터 액세스가 여러 코어에서 캐시를 더럽힐 수 있습니다.

시스템 호출이 syscall이 완료된 후 사용자 공간 코드 성능에 미치는 영향에 대한 자세한 내용은 this paper을 참조하십시오. (드물게 syscalls에 대한 커널 내부의 데이터/명령 캐시 누락에 대해서). 하나의 스레드가 모든 시스템 호출을 처리하는 것, 적어도 모든 시스템 호출을 작성하는 것이 프로세스의 풋 프린트의 일부분을 하나의 코어로 분리하는 것입니다. 커널 내부의 잠금 경합뿐만 아니라

FlexSC 논문은 사용자 -> 커널 -> 사용자 전환을 줄이기위한 시스템 호출 일괄 처리에 대한 아이디어이지만 일반적인 동기 시스템 호출 방법의 오버 헤드도 측정합니다. 더 중요한 것은 시스템 호출로부터 캐시 오염에 대한 논의입니다.


다른 방법으로, 여러 스레드가 로그 파일에 쓸 수있게하면 그냥 대기열을 사용하지 않고 그대로 사용할 수 있습니다.

대용량 쓰기가 중단되지 않을 것이라고 보장 할 수는 없지만 중소 크기 쓰기는 대부분의 OS에서 항상 전체 버퍼를 복사해야합니다. 특히 파이프가 아니라 파일에 쓰는 경우 특히 그렇습니다. IDK는 Linux write()가 선매 (preempted) 될 때 어떻게 동작 하는지를 IDK가 알고 있지만 요청 된 바이트를 모두 쓰지 않고 리턴하지 않고 보통 쓰기를 끝내기를 기대한다. 부분 쓰기는 신호로 인해 중단 될 가능성이 더 높습니다.

두 개의 write() 시스템 호출의 바이트가 함께 혼합되지 않습니다. 한 바이트의 모든 바이트는 다른 바이트의 앞뒤에 있습니다. 그래도 부분 쓰기가 잠재적 인 문제라는 것은 맞습니다. glibc syscall wrapper가 EINTR에 대한 호출을 다시 시작하는지 잊어 버립니다. 이 경우 실제로는 기록 된 바이트가 없거나 바이트 수로 성공을 리턴했을 것입니다.

부분 쓰기 및 성능을 테스트해야합니다. 커널 공간 잠금은 잠금없는 대기열의 오버 헤드보다 저렴할 수 있지만 로그 메시지를 생성하는 모든 스레드에서 시스템 호출을하면 성능이 저하 될 수 있습니다.(그리고 이것을 테스트 할 때 에만 전화 만 쓰는 것이 아니라 사용자 공간 프로세스에서 실제 작업을 수행해야합니다.

+0

감사합니다 :) "그리고 이것을 테스트 할 때, 쓰기 만하는 루프가 아닌 사용자 공간 프로세스에서 실제 작업을 수행해야합니다." 예, 만났습니다. :) - lock-contention :) – Gilgamesz