2010-08-20 5 views
1

정말 이상한 상황이 있습니다. char * 문자열과 관련된 모든 핵심적인 메모리를 사용하여 Linux 멀티 스레딩 C 응용 프로그램을 만들고 있습니다. 정말 이상한 위치에 머물러 있습니다.이상한 C 프로그램 동작

기본적으로 POSIX 스레드를 사용하여 2 차원 char 배열을 읽고 쓰고 있지만 예외적 인 오류가 발생합니다. 독자는 개별적으로 액세스하는 것에 대해 광범위한 테스트를 수행했으며, 다른 스레드의 데이터를 읽지 않고 다른 사람에게 쓸 수는 없다는 것을 알았습니다. 배열과 함께 작동하는 마지막 스레드가 배열의 일부를 변경하면 배열의 마지막 몇 문자가 변경되어 거기에 문자가 들어갈 가능성이 있습니다. 주로 검은 다이아몬드 물음표로 인쇄되는 것들.

저는 valgrind와 GDB를 사용하며 실제로 도움이되지 않습니다. 내가 말할 수있는 한 모두 작동해야합니다. Valgrind는 내가 모든 것을 자유롭게하지 않는다고 말한다.

나는 그 모든 것이 상당히 바람직하지 않다고 생각하지만, 이상하게 여기는 곳이있다. 전기 울타리로 프로그램을 컴파일하면 모든 작품이이다. Valgrind는 내가 모든 것을 해방하고 있으며 메모리 오류가 전혀 없다고 생각합니다. 그것은 절대적으로 완벽하게 작동합니다!

내 질문에 내 전기가 울타리로 컴파일 할 때 내 프로그램이 제대로 작동하는 이유는 무엇입니까?

(또한 단계 100 % "스레드 안전"코드를 확인하기 위해 수행해야 할 어떤 측면 질문?로) 그것은 당신이 당신의 데이터 구조를 부수고있는 것처럼 소리

+1

심령 디버깅 요청? 만약 누군가가 그 이유를 정확하게 추측하면, 그들은 많은 상향 조율을받을 자격이 있습니다 ;-) 처음에는 다른 스레드의 데이터를 읽지 않고 다른 사람들에게 쓰는 것을 허용하지 않고 " 배열과 함께 작동하는 마지막 스레드 "를 참조하십시오. 아마 당신은 비공유 배열의 요소를 의도하지만, 그 중 일부는 실수로 발생합니다. 아마도 스레드 중 하나가 배열의 "일부"를 오버런하여 다른 스레드와 경쟁 상태가 될 수 있습니다. 아마도 전기 담장은 우연히 경기를 피하면서 타이밍을 미묘하게 바꿉니다. –

+3

버그는 42 행에 있습니다. 스레드 안전 코드는 테스트가 아닌 디자인 결과입니다. 솔직히, 당신이하는 일 중 적어도 일부를 보지 않고, 유용한 제안을하는 데 많은 것을 할애하는 것은 불가능합니다. –

+4

코드를 자랑스럽게 생각하는 것은 그것에 대해 질문 할 때 원천 징수하지 않는 것이 좋습니다. –

답변

2

전기 울타리는 당신이 만드는 각 할당, 나는 적어도 두 들었어요 페이지를 할당합니다. OS 페이징 메커니즘을 사용하여 할당 외부에 대한 액세스를 확인합니다. 즉, 새로운 14 자의 배열을 원할 경우, 8k라고하면 완전히 새로운 페이지로 유지하게됩니다. 대부분의 페이지는 사용되지 않지만 사용 된 페이지를 보면서 잘못된 액세스를 감지 할 수 있습니다. 문제가 경비원을 지나치게되면 여분의 공간이 생겨서 오류가 표시되지 않는다고 생각합니다.

잘못된 액세스 권한은 없지만 올바르게 잠기지 않은 두 개의 스레드로 인해 손상된 경우이를 감지하지 못합니다. efence는 할당 된 메모리에 대한 포인터를 유지하여 valgrind를 속여 문제를보고하지 않을 가능성이 있습니다. --show-reachable=yes 플래그로 valgrind를 실행하고 실행 종료시 부인되지 않은 항목을 확인해야합니다.

2

. 배열의 처음과 끝에 카나리아를 놓고 GDB를 연 다음 카나리아에 쓰기 중단 점을 놓으십시오.

카나리아는 변경해서는 안되는 const 값입니다. 유일한 목적은 덮어 써야하는 메모리 손상을 감지하는 것입니다. 예를 들어 :

int the_size_i_need; 
char* array = malloc((the_size_i_need + 2) * sizeof(char)); 
array[0] = 0xAA; 
array[the_size_i_need+1] = 0xFF; 
char* real_array = array+1; 

/* Do some stuff here using real_array */ 

if (array[0] != 0xAA || array[the_size_i_need+1] != 0xFF) { 
    printf("Oh noes! We're corrupted\n"); 
} 
+0

efence가하는 일은 꽤 많이 있습니다 (가드 페이지 사용). 카나리아를 다른 스레드가 사용하는 배열 비트 사이의 경계에 놓는 것은 효과적 일 수 있습니다. 물론, 에센스가 거기에 갈 수 없기 때문에. –

0

오, 이런, 정말 죄송합니다. 나는 그것을 풀어 냈다. 각각에 대한 답을 넣을 수있는 변수가 스레드에 주어졌지만, 0으로 정의하지 않았고 2 개의 재미있는 문자가 포함되어있다. 어쩌면 전기 펜스 malloc()은 calloc()과 같이 'zeroed'메모리를 할당하지만 표준 malloc()은 물론 그렇지 않습니다.