문제

코드를 검토하고 있으며 사용되는 기술이 의심 스럽습니다.

Linux 환경에는 여러 공유 메모리 세그먼트를 연결하는 두 가지 프로세스가 있습니다. 첫 번째 프로세스는 공유 할 새 파일 세트를 주기적으로로드하고 공유 메모리 ID (SHMID)를 "마스터"공유 메모리 세그먼트의 위치에 기록합니다. 두 번째 프로세스는이 "마스터"위치를 지속적으로 읽고 SHMID를 사용하여 다른 공유 세그먼트를 첨부합니다.

멀티 -CPU 호스트에서는 한 프로세스가 다른 프로세스가 메모리를 읽는 동안 메모리를 읽으려고 할 때 어떤 일이 발생하는지에 따라 구현 될 수 있습니다. 그러나 아마도 하드웨어 수준의 버스 잠금 장치는 와이어의 곰팡이 비트를 방지합니까? 읽기 과정이 매우 변화하기 시작한 값을 얻었는지 여부는 중요하지 않을 것입니다. 읽기가 오래된 가치 나 새로운 가치가 아닌 무언가에 손상된 경우에만 중요합니다. 이것은 가장자리 케이스입니다. 32 비트 만 쓰고 읽습니다.

SHMAT에 대한 인터넷 검색으로 인해이 영역에서 결정적인 것은 없었습니다.

나는 그것이 안전하거나 제정신이 아니라고 강력하게 의심하며, 내가 정말로 원하는 것은 문제를 자세히 설명하는 기사에 대한 포인터입니다.

도움이 되었습니까?

해결책

OS에서는 당신이 그것을하는 것을 막지 않을 것입니다.

그러나 그것은 똑똑합니까? 아니요, 일부 유형의 동기화가 있어야합니다.

"와이어에 엉망인 비트"가 없을 것입니다. 그들은 하나 또는 0으로 나올 것입니다. 그러나 다른 프로세스가 읽기 전에 모든 비트가 기록 될 것이라고 말할 것이 없습니다. 그리고 그들이 얼마나 빨리 쓰여질 지, 얼마나 빨리 읽을 것인지에 대한 보장은 없습니다.

당신은 항상 2 개의 프로세스 (또는 그 문제에 대한 스레드) 사이에 전혀 관계가 없다고 가정해야합니다.

하드웨어 레벨 버스 잠금은 제대로 얻지 않으면 발생하지 않습니다. 컴파일러 / 라이브러리 / OS / CPU가 올바르게 얻을 수 있도록 더 어려울 수 있습니다. 동기화 프리미티브는 올바르게 발생하는지 확인하기 위해 작성되었습니다.

잠금은 안전하게 만들 것이며 그렇게하기 어렵지 않습니다. 그러니 그냥 해요.


@unkNown- 답변이 게시 된 이후 질문이 다소 변경되었습니다. 그러나 설명하는 동작은 도전적으로 플랫폼 (하드웨어, OS, 라이브러리 및 컴파일러)에 종속됩니다.

컴파일러 특정 지침을 제공하지 않으면 실제로 한 번의 샷으로 32 비트를 기록 할 수는 없습니다. 32 비트 단어가 단어 경계에 정렬되지 않은 상황을 상상해보십시오. 이 정렬되지 않은 액세스는 X86에서 허용되며 X68의 경우 액세스는 CPU에 의한 일련의 정렬 된 액세스로 바뀝니다.

해당 작업간에 인터럽트가 발생할 수 있습니다. 컨텍스트 스위치가 중간에 발생하면 일부 비트가 쓰여지지 않으면 일부는 그렇지 않습니다. 뱅, 넌 죽었다.

또한 약 16 비트 CPU 또는 64 비트 CPU를 생각해 보겠습니다. 둘 다 여전히 인기가 있으며 반드시 당신이 생각하는 방식으로 작동하지는 않습니다.

따라서 실제로 "다른 CPU 코어가 단어 크기의 가치를 1/2로 뽑는 상황"이있는 상황을 가질 수 있습니다. 동기화를 사용하지 않으면 이러한 유형의 일이 발생할 것으로 예상되는 것처럼 코드를 작성합니다.

이제, 당신의 글을 미리 정보를 제공하여 전체 단어를 작성할 수 있도록하는 방법이 있습니다. 이러한 방법은 동기화 범주에 속하며 동기화 프리미티브를 만드는 것은 라이브러리, 컴파일러, OS 및 하드웨어 설계자에게 가장 적합한 유형입니다. 특히 휴대성에 관심이있는 경우 (코드를 포트하지 않더라도)

다른 팁

문제는 실제로 일부 사람들이 논의한 것보다 더 나쁩니다. Zifre는 현재 X86 CPUS 메모리 쓰기가 원자력이라는 것이 옳습니다. 그러나 그것은 사실이되기 위해 빠르게 중단됩니다. 메모리 쓰기는 단일 코어에 대해서만 원자입니다. 다른 코어는 같은 순서로 쓰기를 볼 수 없습니다.

다시 말해서

a = 1;
b = 2;

CPU 2에서는 위치가 표시 될 수 있습니다 b 위치 'a'는 위치 전에 수정됩니다. 또한 기본 단어 크기 (X32 프로세서의 32 비트)보다 큰 값을 쓰는 경우, 쓰기는 원자가되지 않으므로 64 비트 쓰기의 32 비트가 낮은 시간과 다른 시간에 버스에 부딪칩니다. 32 비트의 쓰기. 이것은 물건을 엄청나게 복잡하게 할 수 있습니다.

메모리 장벽을 사용하면 괜찮을 것입니다.

당신은 어딘가에 잠그는 것이 필요합니다. 코드 레벨이 아닌 경우 하드웨어 메모리 캐시 및 버스에 있습니다.

당신은 아마도 펜티엄 프로 인텔 CPU에서 괜찮을 것입니다. 방금 읽은 바에 따르면 인텔은 나중에 CPU가 본질적으로 기계 코드의 잠금 접두사를 무시하게 만들었습니다. 대신 캐시 일관성 프로토콜은 모든 CPU간에 데이터가 일관되도록해야합니다. 따라서 코드가 캐시 라인 경계를 넘지 않는 데이터를 작성하면 작동합니다. 메모리의 순서는 크로스 캐시 라인이 보장되지 않으므로 멀티 워드 쓰기는 위험합니다.

x86 또는 x86_64 이외의 것을 사용하는 경우 괜찮지 않습니다. 많은 비 인쇄 CPU (및 아마도 인텔 이타늄)는 명시 적 캐시 일관성 기계 명령을 사용하여 성능을 얻고 (사용자 정의 ASM 코드, 컴파일러 인트린틱 또는 라이브러리를 통해) 사용하지 않으면 캐시를 통해 메모리에 쓰는 것은 보장되지 않습니다. 항상 다른 CPU로 보이거나 특정 순서로 발생합니다.

따라서 Core2 시스템에서 작동한다고해서 코드가 올바른 것을 의미하지는 않습니다. 이식성을 확인하려면 PPC (이전 MacPro 또는 셀 블레이드) 또는 Itanium 또는 IBM 전력 또는 암과 같은 다른 SMP 아키텍처에서도 코드를 사용해보십시오. 알파는 나쁜 SMP 코드를 공개하기위한 훌륭한 CPU 였지만, 당신이 하나를 찾을 수 있을지 의심 스럽다.

두 개의 프로세스, 2 개의 스레드, 2 개의 CPU, 2 개의 코어는 모두 메모리를 통해 데이터를 공유 할 때 특별한주의가 필요합니다.

이 IBM 기사는 옵션에 대한 훌륭한 개요를 제공합니다.

Linux 동기화 방법의 해부학M. Tim Jones (mtj@mtjones.com), 컨설턴트 엔지니어, Emulex의 커널 원자학, 스핀 락 및 뮤 테스

http://www.ibm.com/developerworks/linux/library/l-linux-synchronization.html

나는 실제로 이것이 완전히 안전해야한다고 생각합니다 (그러나 정확한 구현에 따라 다릅니다). "마스터"세그먼트가 기본적으로 배열이라고 가정하면, SHMID가 원자 적으로 작성 될 수있는 한 (32 비트 인 경우 괜찮을 것입니다) 두 번째 프로세스는 읽기 만하면 괜찮을 것입니다. 잠금 장치는 두 프로세스가 모두 쓰는 경우에만 필요합니다. 또는 기록되는 값은 원자 적으로 기록 할 수 없습니다. 당신은 결코 손상되지 않을 것입니다 (절반의 서면 값). 물론, 이것을 처리 할 수없는 이상한 아키텍처가있을 수 있지만 x86/x64에는 괜찮을 것입니다 (아마도 Arm, PowerPC 및 기타 일반적인 아키텍처).

읽다 현대 마이크로 프로세서에서의 메모리 순서, 파트 I. 그리고 파트 II

그들은 이것이 왜 이론적으로 안전하지 않은지에 대한 배경을줍니다.

잠재적 인 경주는 다음과 같습니다.

  • 프로세스 A (CPU Core a)는 새로운 공유 메모리 영역에 씁니다.
  • 공유 메모리 ID를 공유 32 비트 변수로 처리 한 풋을 처리합니다 (32 비트 정렬-모든 컴파일러는 이와 같이 정렬하려고합니다).
  • 프로세스 B (CPU 코어 B에서)는 변수를 읽습니다. 32 비트 크기와 32 비트 정렬을 가정하면 실제로 쓰레기가 발생하지 않아야합니다.
  • 프로세스 B는 공유 메모리 영역에서 읽으려고합니다. 이제 메모리 장벽을 놓치었기 때문에 A가 작성한 데이터가 보일 것이라는 보장은 없습니다. (실제로, 공유 메모리 세그먼트를 매핑하는 라이브러리 코드의 CPU B에 메모리 장벽이 있었을 것입니다. 문제는 프로세스 A가 메모리 장벽을 사용하지 않았다는 것입니다).

또한이 디자인으로 공유 메모리 영역을 안전하게 자유롭게 자유롭게 해제 할 수있는 방법은 확실하지 않습니다.

최신 커널과 LIBC를 사용하면 pthreads mutex를 공유 메모리 영역에 넣을 수 있습니다. (이것은 NPTL이있는 최근 버전이 필요합니다. 저는 Debian 5.0 "Lenny"를 사용하고 있으며 잘 작동합니다). 공유 변수 주변의 간단한 잠금은 비전 메모리 장벽 문제에 대해 걱정할 필요가 없다는 것을 의미합니다.

나는 당신이 이것을 묻는 것을 믿을 수 없습니다. 아니 반드시 안전하지는 않습니다. 최소한 이는 컴파일러가 SHMID를 설정할 때 공유 메모리 위치를 원자 적으로 설정하는 코드를 생성하는지 여부에 따라 다릅니다.

이제 Linux를 모르지만 Shmid가 16 ~ 64 비트라고 생각합니다. 즉, 모든 플랫폼 이이 값을 원자 적으로 쓸 수있는 몇 가지 지침을 가질 수 있습니다. 그러나 어떻게 든 질문하지 않고 컴파일러에 의존 할 수 없습니다.

메모리 구현에 대한 세부 사항은 가장 플랫폼 특정 사항 중 하나입니다!

BTW, 귀하의 경우에는 중요하지 않을 수 있지만 일반적으로 단일 CPU 시스템에서도 잠금에 대해 걱정해야합니다. 일반적으로 일부 장치는 공유 메모리에 쓸 수 있습니다.

나는 그것이 효과가있을 수 있다는 데 동의하므로 안전하지만 제정신은 아닐 수도 있습니다. 주요 질문은이 저수준 공유가 실제로 필요한지 여부입니다. 저는 Linux의 전문가가 아니지만 예를 들어 마스터 공유 메모리 세그먼트의 FIFO 대기열을 사용하여 OS가 잠금 작업을 수행하도록 고려할 것입니다. . 소비자/생산자는 일반적으로 동기화를 위해 줄이 필요합니다.

합법적인? 나는 생각한다. "관할 구역"에 따라 다릅니다. 안전하고 제정신? 거의 확실하지 않습니다.

편집 : 더 많은 정보로 이것을 업데이트하겠습니다.

당신은보고 싶을 수도 있습니다 이것 Wikipedia 페이지; 특히 "자원에 대한 조정"에 관한 섹션. 특히, Wikipedia 토론은 본질적으로 a 신뢰 실패; 공유 자원에 대한 잠금화되지 않은 액세스는 원자 자원의 경우에도 신뢰 행동이 이루어졌다. 본질적으로, 자원을 수정할 수 있는지 여부를 확인하기 위해 점검 사이의 기간 동안 리소스가 외부로 수정되므로 조건부 점검에 내재 된 신뢰가 파열됩니다.

나는 여기있는 사람이 버스를 통해, 특히 제한된 시스템과 함께 버스 대역에서 얼마나 많은 충격 잠금 경쟁이 가질 수 있는지 논의했다고 생각하지 않습니다.

여기 이 문제에 대한 기사는 어느 정도 깊이 있는데, 그들은 버스를 통한 독점 액세스에 대한 전반적인 수요를 바꾸는 대체 스케줄링 조류에 대해 논의합니다. 경우에 따라 Naieve 스케줄러보다 60% 이상의 총 처리량이 증가합니다 (명시 적 잠금 접두사 명령 또는 암시 적 XCHG CMPX의 비용을 고려할 때). 이 논문은 가장 최근의 작업이 아니며 실제 코드 (Dang Academic 's)를 방해하지는 않지만이 문제에 대한 읽기와 고려의 가치가 있습니다.

보다 최근의 CPU ABI는 단순보다 대체 작업을 제공합니다. 자물쇠 무엇이든.

제프, FreeBSD (많은 내부 커널 구성 요소의 저자)의, Monitor 및 Mwait, SSE3에 대해 2 개의 지침에 대해 설명하면서 간단한 테스트 사례에서 20%의 개선을 확인했습니다. 그는 나중에 가정한다.

따라서 이것은 이제 적응 형 알고리즘의 첫 번째 단계이며, 우리는 잠시 회전 한 다음 고전력 상태에서 잠을 자고 부하에 따라 저전력 상태에서 잠을 자고 있습니다.

...

대부분의 경우 우리는 여전히 HLT에서도 공회전하고 있으므로 전력에 부정적인 영향을 미치지 않아야합니다. 실제로, 유휴 상태에 들어가서 빠져 나가는 데 많은 시간과 에너지가 낭비되므로 필요한 총 CPU 시간을 줄임으로써 부하의 전력을 향상시킬 수 있습니다.

HLT 대신 일시 정지를 사용하는 효과가 무엇인지 궁금합니다.

에서 인텔의 TBB;

        ALIGN 8
        PUBLIC __TBB_machine_pause
__TBB_machine_pause:
L1:
        dw 090f3H; pause
        add ecx,-1
        jne L1
        ret
end

조립의 예술 또한 잠금 접두사 또는 XCHG 사용과 함께 동시 화를 사용합니다. 나는 그 책을 한동안 읽지 않았으며 사용자 지대 보호 모드 SMP 컨텍스트에서 적용 가능성에 직접 말하지는 않지만 살펴볼 가치가 있습니다.

행운을 빕니다!

SHMID에 다른 유형이있는 경우 volatile sig_atomic_t 그러면 동일한 CPU에서도 별도의 스레드가 문제가 될 것이라고 확신 할 수 있습니다. 유형이있는 경우 volatile sig_atomic_t 그렇다면 확실하지는 않지만 멀티 스레딩이 신호보다 더 많은 인터리빙을 할 수 있기 때문에 여전히 운이 좋을 수도 있습니다.

SHMID가 캐시 라인을 가로 지르는 경우 (부분적으로 한 캐시 라인에서 그리고 부분적으로 다른 경우), 쓰기 CPU가 쓰는 동안 새로운 가치의 일부와 이전 값의 일부를 읽는 CPU 읽기 부분을 찾습니다.

이것이 바로 "비교 및 스왑"과 같은 지침이 발명 된 이유입니다.

독자 작성자 잠금 장치가 필요한 것 같습니다. http://en.wikipedia.org/wiki/readers-writer_lock.

대답은 - 읽기와 동시에 쓰는 것이 절대적으로 안전하다는 것입니다.

SHM 메커니즘은 사용자에게 베어 본 도구를 제공하는 것이 분명합니다. 모든 액세스 제어는 프로그래머가 처리해야합니다. 잠금 및 동기화는 커널에 의해 친절하게 제공되고 있으며, 이는 사용자가 인종 조건에 대한 걱정이 적다는 것을 의미합니다. 이 모델은 프로세스간에 데이터를 공유하는 대칭적인 방법 만 제공합니다. 프로세스가 다른 프로세스에 새로운 데이터가 공유 메모리에 삽입되었음을 알리려면 신호, 메시지 대기열, 파이프, 소켓 또는 기타 유형의 IPC를 사용해야합니다.

에서 Linux에서 공유 메모리 기사.

최신 Linux SHM 구현은 방금 사용합니다 copy_to_user 그리고 copy_from_user 내부적으로 메모리 버스와 동기화 된 통화.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top