Курьезный случай в параллельном программировании

У меня есть параллельная программа, которая иногда запускается, а иногда просто дает ошибку сегментации. Исполняемый файл при принудительном запуске с 3 потоками работает нормально (в основном он также работает с одним потоком, который является просто последовательным), но выдает ошибку сегментации при принудительном запуске с любым другим значением потока. Вот сценарий:

Из main.c внутри основной функции:

cilk_for ( line_count = 0; line_count != no_of_lines ; ++line_count )
{
     //some stuff here
     for ( j=line_count+1; j<no_of_lines; ++j )
     {
         //some stuff here
         final_result[line_count][j] = bf_dup_eleminate ( table_bloom[line_count], file_names[j], j );
         //some stuff here
     }
     //some stuff here
}

bf_dup_eleminate функция из bloom-filter.c файла:

int bf_dup_eleminate ( const bloom_filter *bf, const char *file_name, int j )
{
    int count=-1;
    FILE *fp = fopen (file_name, "rb" );
    if (fp)
    {
        count = bf_dup_eleminate_read ( bf, fp, j);
        fclose ( fp );
    }
    else
    {
        printf ( "Could not open file\n" );
    }
    return count;
}

bf_dup_eleminate_read из bloom-filter.c файла:

int bf_dup_eleminate_read ( const bloom_filter *bf, FILE *fp, int j )
{
    //some stuff here
    printf ( "before while loop. j is %d ** workder id: **********%d***********\n", j, __cilkrts_get_worker_number());
    while (/*somecondition*/)
    {/*some stuff*/}
    //some stuff
}

Я получил сообщение об этой ошибке от intel inspector:

ID | Problem                         |  Sources       
P1 | Unhandled application exception | bloom-filter.c

и стек вызовов:

exec!bf_dup_eleminate_read - bloom-filter.c:550
exec!bf_dup_eleminate - bloom-filter.c:653
exec!__cilk_for_001.10209 - main.c:341

Точно так же gdb также сообщает об ошибке в том же месте, и это:

Теперь gdb говорит мне, что у вас есть следующая ошибка

0x0000000000406fc4 in bf_dup_eleminate_read (bf=<error reading variable: Cannot access memory at address 0x7ffff7edba58>, fp=<error reading variable: Cannot access memory at address 0x7ffff7edba50>, j=<error reading variable: Cannot access memory at address 0x7ffff7edba4c>) at bloom-filter.c:536

Line 536 is int bf_dup_eleminate_read ( const bloom_filter *bf, FILE *fp, int j )

Дополнительные детали:

Теперь мой фильтр цветения представляет собой структуру, определенную как

struct bloom_filter
{
    int64_t m;      //size of bloom filter.
    int32_t k;      //number of hash functions.
    uint8_t *array;
    int64_t no_of_elements_added;
    int64_t expected_no_of_elements;
};

и память для него выделяется так:

    bloom_filter *bf = (bloom_filter *)malloc( sizeof(bloom_filter));
    if ( bf != NULL )
    {
        bf->m = filter_size*8;      /* Size of bloom filter */
        bf->k = num_hashes;
        bf->expected_no_of_elements = expected_no_of_elements;
        bf->no_of_elements_added = (int64_t)0;
        bf->array = (uint8_t *)malloc(filter_size);
        if ( bf->array == NULL )
        {
            free(bf);
            return NULL;
        }
    }  

Существует только одна копия bloom_filter, и каждый поток должен иметь доступ к одному и тому же (поскольку я ничего не изменяю, только читаю).

Может ли кто-нибудь помочь мне, потому что я застрял здесь последние 4 дня и просто не могу придумать выхода. Хуже всего то, что он работает на 3 потока!!!

Примечание: cilk_for — это просто ключевое слово для создания потоков в cilk.


person Aman Deep Gautam    schedule 02.07.2012    source источник
comment
похоже, у вас есть дефект в распределении bloom_filter, когда после выполнения malloc() для массива bf-› вы проверяете NULL для массива bf, а не для массива bf-›. Это не ваша проблема, просто я заметил.   -  person Richard Chambers    schedule 02.07.2012
comment
Я признаю, что это была ошибка, но я запустил обновленный код, и он не сработал. Не могли бы вы предложить другую возможность для такой ошибки   -  person Aman Deep Gautam    schedule 02.07.2012
comment
Появляется из-за ошибки вы обращаетесь к памяти, которая вам не принадлежит. Другое немедленное изменение, которое я бы сделал, — это условный оператор cilk_for(), я бы использовал line_count ‹ no_of_lines, а не !=. Могу ли я предположить, что no_of_lines на самом деле является количеством одновременно выполняемых потоков? Похоже, вы разделяете работу между несколькими потоками, каждый из которых будет использовать bf_dup_eleminate() для выполнения части задания, однако код не имеет смысла в том, как он индексирует таблицу final_result.   -  person Richard Chambers    schedule 02.07.2012
comment
Также ознакомьтесь с этой статьей гонка данных для cilk_for, а также эту статью исправление условий гонки для cilk_for   -  person Richard Chambers    schedule 02.07.2012
comment
Теперь я тоже думаю о том же, и в сообщении об ошибке также довольно четко указано, но почему это происходит. Дело в том, что память, выделенная потоком, должна использоваться только этим потоком (я так не думаю, поскольку это имеет меньше смысла). Что касается количества потоков, цикл cilk_for создает log(no_of_lines) для базовых 2 задач, а затем присваивает его количеству потоков, навязанному программистом для использования программой.   -  person Aman Deep Gautam    schedule 02.07.2012
comment
Кстати, в вашем списке распределения памяти bloom_filter, я уверен, вы хотели написать if ( bf->array == NULL ) { free(bf); ... } в качестве последнего утверждения, не так ли... :-)   -  person aps2012    schedule 02.07.2012
comment
Да, я исправил это. Было глупо с моей стороны совершить эту ошибку, я не знаю, как я забыл об этом. Что ж, я пришел к выводу, что всякий раз, когда два потока обращаются к одной и той же ячейке памяти, возникает ошибка, поэтому я предполагаю, что, когда вы явно не указываете, что вы обращаетесь к этой ячейке только для чтения, вам предоставляется эксклюзивная блокировка. Я думаю, что это проблема. Я прав??   -  person Aman Deep Gautam    schedule 02.07.2012


Ответы (1)


Когда отладчик сообщает вам об ошибке, подобной этой:

0x0000000000406fc4 in bf_dup_eleminate_read (
    bf=<error reading variable: Cannot access memory at address 0x7ffff7edba58>,
    fp=<error reading variable: Cannot access memory at address 0x7ffff7edba50>,
    j=<error reading variable: Cannot access memory at address 0x7ffff7edba4c>
) at bloom-filter.c:536

536: int bf_dup_eleminate_read ( const bloom_filter *bf, FILE *fp, int j )

обычно это указывает на то, что код входа в функцию (называемый "прологом" функции) дает сбой. Короче говоря, ваш стек поврежден, и процессор дает сбой, когда вычисляет адреса трех локальных переменных и выделяет для них место в стеке.

Вещи, которые я бы проверил или попытался исправить эту ошибку (ни одна из них не гарантирует работу, а некоторые из них вы, возможно, уже пробовали):

  1. Убедитесь, что вы не переполняете пространство, используемое локальными переменными, которые вы объявили в других частях вашей программы.

  2. Убедитесь, что вы не пишете в указатели, которые были объявлены как локальные переменные, а затем возвращены из функции в других частях вашей программы.

  3. Убедитесь, что у каждого потока достаточно места в стеке для обработки всех объявленных вами локальных переменных. Вы объявляете какие-либо большие буферы на основе стека? Размер стека по умолчанию для каждого потока зависит от настроек компилятора или, в данном случае, от библиотеки cilk. Попробуйте увеличить размер стека для каждого потока во время компиляции и посмотрите, исчезнет ли сбой.

Если повезет, один из вышеперечисленных должен позволить вам сузить источник проблемы.

person aps2012    schedule 02.07.2012
comment
Такс человек !! ты обалденный. Я застрял здесь в течение последних 5 дней, и я пробовал все. Я изучил 3 новых софта и делал все, что мог, но это не помогло. Именно из-за третьего пункта и вылет уходит.. :). Еще раз большое спасибо - person Aman Deep Gautam; 02.07.2012
comment
@ Аман, я был в похожей ситуации. aps2012, вы сэкономили мне много минут разочарования :) перемещение пары больших массивов из локальной функции в глобальную область решило проблему: D. Я получал segfaults при объявлении функции. - person Max Wallace; 17.10.2013