Странное поведение программы на C - PullRequest
1 голос
/ 21 августа 2010

У меня действительно странная ситуация. Я делаю многопоточное приложение C на Linux, используя все мелкие детали памяти, включая строки char *, и я застрял в действительно странном положении.

По сути, при использовании потоков POSIX я читаю и записываю данные в двумерный массив символов, но в нем есть необычные ошибки. У меня есть слово, что я провел обширное тестирование того, к чему они имеют индивидуальный доступ, и они не читают данные других потоков, не говоря уже о том, чтобы писать другим. Когда последний поток, работающий с массивом, меняет свои части массива, он, похоже, меняет последние несколько символов своих массивов и помещает туда символы, которые я не знаю, как они могли туда попасть; в основном те, которые печатают как черные знаки вопроса с бриллиантами.

Я использую valgrind и GDB, и они действительно не помогают. Насколько я могу сказать, все должно работать. Вальгринд говорит мне, что я не освобождаю все.

Я знаю все, что звучит довольно неописуемо, но вот где это становится странным: если я компилирую свою программу с электрическим забором, то она все работает . Вальгринд говорит мне, что я освобождаю все и что в памяти вообще нет ошибок, как я и думал. Работает абсолютно без нареканий!

Итак, я предполагаю, что мой вопрос: почему моя программа работает нормально при компиляции с электрическим забором?

(А также дополнительный вопрос: какие шаги необходимо предпринять, чтобы обеспечить 100% -ный «потокобезопасный» код?)

Ответы [ 3 ]

2 голосов
/ 21 августа 2010

Электрический забор распределяет страницы, я слышал, по крайней мере, две, для каждого распределения, которое вы делаете. Он использует механизмы подкачки ОС для проверки доступа за пределами выделения. Это означает, что если вы хотите новый 14-символьный массив, вы получите целую новую страницу, например 8k. Большая часть страницы не используется, но вы можете обнаружить ошибочный доступ, просмотрев, какие страницы используются. Я могу себе представить, что из-за наличия такого большого дополнительного пространства, если проблема пройдет мимо охранников, вы не увидите ошибки.

Если у вас нет плохого доступа, а есть повреждение из-за неправильной блокировки двух потоков, efence его не обнаружит. efence также, вероятно, сохраняет указатели на выделенную память, обманывая Вальгринда в сообщении о проблемах. Вы должны запустить valgrind с флагом --show-reachable=yes и посмотреть, что невостребовано в конце вашего бега.

2 голосов
/ 21 августа 2010

Звучит так, будто вы разрушаете свои структуры данных. Попробуйте поместить канарейки в начале и конце ваших массивов, откройте GDB, а затем запишите контрольные точки на канареках.

Канарейка - это постоянное значение, которое никогда не следует изменять - его единственная цель - обнаружить повреждение памяти в случае ее перезаписи. Например:

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 голосов
/ 21 августа 2010

О Боже, мне очень жаль. Я разобрался с этим: каждому потоку была дана переменная, в которую нужно было дать ответ, но я не определил ее как ноль, и он содержит 2 забавных символа. Может быть, электрический забор malloc () выделяет «обнуленную» память, как calloc (), но стандартный malloc (), конечно, не делает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...