문제

공유 메모리에 참조 계산 개체가 있다고 가정합니다.참조 카운트는 객체를 사용하는 프로세스의 수를 나타내며 프로세스는 원자적 명령을 통해 카운트를 늘리고 줄이는 역할을 담당하므로 참조 카운트 자체도 공유 메모리에 있습니다(객체의 필드일 수도 있고 객체의 필드일 수도 있음). 개수에 대한 포인터가 포함될 수 있으므로 이 문제를 해결하는 데 도움이 되는 제안이 있으면 환영합니다.)때때로 프로세스에 카운트 감소를 방지하는 버그가 있을 수 있습니다.어떤 프로세스가 카운트를 감소시키지 않는지 알아내는 것을 최대한 쉽게 만들려면 어떻게 해야 합니까?

제가 생각한 한 가지 해결책은 각 프로세스에 UID(아마도 PID)를 제공하는 것입니다.그런 다음 프로세스가 감소하면 UID를 참조 카운트와 함께 저장된 연결 목록에 푸시합니다. 카스).디버깅하려는 경우 공유 메모리에 아직 살아있는 개체의 연결된 목록을 보는 특수 프로세스가 있으며 목록에 없는 앱의 UID는 아직 개수가 감소하지 않은 앱입니다.

이 솔루션의 단점은 O(N) 메모리 사용량이 있다는 것입니다. 여기서 N은 프로세스 수입니다.공유 메모리 영역을 사용하는 프로세스 수가 많고 개체 수가 많으면 비용이 빨리 발생합니다.부분적으로 고정된 크기 정보를 사용하면 단일 프로세스를 정확히 찾아낼 수 없더라도 가능한 프로세스 목록의 범위를 좁힐 수 있어 디버깅을 지원할 수 있는 중간 솔루션이 있을 수 있다고 생각합니다.또는 단일 프로세스만 감소하지 않았는데 어떤 프로세스가 감소하지 않았는지 감지할 수 있는 경우(예:개수를 줄이는 데 실패한 2개 이상의 프로세스 감지를 처리할 수 없음) 이는 여전히 큰 도움이 될 것입니다.

(이 문제에 대한 더 많은 '인간' 솔루션이 있습니다. 예를 들어 모든 응용 프로그램이 동일한 라이브러리를 사용하여 공유 메모리 영역에 액세스하도록 하는 것입니다. 그러나 공유 영역이 바이너리 인터페이스로 처리되고 모든 프로세스가 다음에서 작성된 응용 프로그램이 되지 않는 경우 당신은 통제할 수 없는 사람이에요.또한 모든 앱이 동일한 라이브러리를 사용하더라도 한 앱에는 라이브러리 외부에 버그가 있어 메모리가 감소하지 못하도록 메모리가 손상될 수 있습니다.예, C/C++와 같은 안전하지 않은 언어를 사용하고 있습니다.)

편집하다:단일 프로세스 상황에서는 제어할 수 있으므로 다음을 사용할 수 있습니다. 라이 (C++에서).

도움이 되었습니까?

해결책

객체 당 하나의 추가 정수 만 사용하여이를 수행 할 수 있습니다.

정수를 0으로 초기화합니다. 프로세스가 객체의 참조 수를 증가 시키면 정수로 PID를 XORS :

object.tracker ^= self.pid;

프로세스가 참조 수를 줄이면 동일합니다.

참조 수가 1에 남아 있으면 추적기 정수는 프로세스의 PID와 동일합니다.


이것은 XOR이 정류적이기 때문에 작동합니다 ( (A ^ B) ^ C == A ^ (B ^ C) ), 프로세스가 자체 PID로 트래커를 횟수 균일하게 XORED하는 것과 동일합니다. PID ^ PID - 그것은 0이므로 추적기 값이 영향을받지 않습니다.

대안으로 서명되지 않은 값 (오버플로보다 랩으로 정의 됨)을 사용할 수 있습니다.

다른 팁

근본적으로 공유 메모리 공유 상태는 강력한 솔루션이 아니며 이를 강력하게 만드는 방법을 모릅니다.

궁극적으로 프로세스가 종료되면 모든 비공유 리소스가 운영 체제에 의해 정리됩니다.이것은 스레드 대신 프로세스(fork())를 사용함으로써 얻을 수 있는 큰 이점입니다.

그러나 공유 리소스는 그렇지 않습니다.다른 사람이 연 파일 핸들은 분명히 닫히지 않았으며 ... 공유 메모리.공유 리소스는 이를 공유하는 마지막 프로세스가 종료된 후에만 닫힙니다.

공유 메모리에 PID 목록이 있다고 상상해 보세요.프로세스는 좀비를 찾기 위해 이 목록을 스캔할 수 있지만 PID가 재사용되거나 앱이 충돌하는 대신 중단될 수 있습니다.

내가 추천하는 것은 각 프로세스 사이에 파이프나 기타 메시지 전달 기본 요소를 사용하는 것입니다(때로는 자연스러운 마스터-슬레이브 관계가 있고 다른 경우에는 모두가 모두와 대화해야 합니다).그런 다음 프로세스가 종료되면 이러한 연결을 닫는 운영 체제를 활용하여 해당 이벤트에서 동료에게 신호를 보냅니다.또한 ping/pong 시간 초과 메시지를 사용하여 피어가 중단되었는지 확인할 수 있습니다.

프로파일링 후에 이러한 메시지에 실제 데이터를 보내는 것이 너무 비효율적이라면 운영 체제가 정리하는 일종의 스트림에 대한 제어 채널을 유지하는 한 페이로드에 공유 메모리를 사용할 수 있습니다.

리소스 소유권에 대한 가장 효율적인 추적 시스템은 참조 보유자 목록은 물론 참조 개수도 사용하지 않습니다.메모리에 존재할 수 있는 모든 데이터 유형의 레이아웃에 대한 정적 정보, 모든 함수의 스택 프레임 모양, 모든 객체에는 유형 표시기가 있습니다.따라서 디버깅 도구는 모든 스레드의 스택을 스캔하고 메모리의 모든 개체에 대한 맵과 서로 참조하는 방법을 얻을 때까지 개체에 대한 참조를 반복적으로 추적할 수 있습니다.그러나 물론 이 기능을 갖춘 시스템에는 자동 가비지 수집 기능도 있습니다.객체 및 스택 프레임의 레이아웃에 대한 모든 정보를 얻으려면 컴파일러의 도움이 필요하며 그러한 정보는 실제로 모든 경우에 C/C++에서 안정적으로 얻을 수 없습니다(객체 참조는 공용체 등에 저장될 수 있기 때문입니다). 게다가 런타임 시 참조 계산보다 훨씬 더 나은 성능을 발휘합니다.

귀하의 질문에 따르면 "퇴화"의 경우 프로세스 상태의 전부(또는 거의 전부)가 스택의 로컬 변수와 별도로 공유 메모리에 보관됩니다.그리고 그 시점에서는 단일 프로세스에서 다중 스레드 프로그램과 정확히 동등한 것을 갖게 됩니다.또는 달리 말하면, 충분한 메모리를 공유하는 프로세스가 스레드와 구별할 수 없게 되기 시작합니다.

이는 질문의 "다중 프로세스, 공유 메모리" 부분을 지정할 필요가 없음을 의미합니다.참조 카운팅을 사용하려고 할 때 누구나 직면하는 것과 동일한 문제에 직면하게 됩니다.스레드를 사용하는 사람(또는 공유 메모리를 무제한으로 사용하는 사람,마찬가지) 또 다른 문제에 직면하게 됩니다.둘을 합치면 고통의 세계가 있습니다.

일반적으로 가능한 경우 스레드 간에 변경 가능한 개체를 공유하지 않는 것이 좋습니다.참조 카운트가 있는 객체는 카운트가 수정될 수 있으므로 변경 가능합니다.즉, (유효한) 스레드 간에 변경 가능한 개체를 공유하고 있습니다.

공유 메모리 사용이 GC와 유사한 것이 필요할 만큼 복잡하다면 두 가지 측면 모두에서 거의 최악의 결과를 얻은 것입니다.프로세스 격리의 이점 없이 프로세스 생성 비용이 많이 듭니다.스레드 간에 변경 가능한 개체를 공유하는 다중 스레드 애플리케이션을 (실제로) 작성했습니다.

로컬 소켓은 프로세스 간 통신을 위한 매우 크로스 플랫폼이자 매우 빠른 API입니다.기본적으로 모든 Unices와 Windows에서 동일하게 작동하는 유일한 것입니다.따라서 이를 최소한의 의사소통 채널로 활용하는 것을 고려해보세요.

그런데 참조를 보유하는 프로세스에서 스마트 포인터를 일관되게 사용하고 있습니까?이것이 참조 계산을 절반이라도 제대로 할 수 있는 유일한 희망입니다.

다음을 사용하십시오

int pids[MAX_PROCS]
int counter;

증가

do
   find i such pid[i]=0  // optimistic
while(cas[pids[i],0,mypid)==false)
my_pos = i;
atomic_inc(counter)

감소

pids[my_pos]=0
atomic_dec(counter);

따라서이 객체를 사용하여 모든 프로세스를 알고 있습니다

MAX_PROCS 충분히 크고 자유로운 장소를 무작위로 검색하여 프로세스 수가 중요하게 낮 으면 MAX_PROCS 검색은 매우 빠릅니다.

직접 작업을 수행합니다. 참조 계산 된 Memchecker가있는 AQTIME과 같은 도구를 사용할 수도 있습니다.

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