Как прибивать программу с OpenMP ?
От: Кодт Россия  
Дата: 09.04.14 16:14
Оценка:
Дано: консольная программа, портируемая под винды и линукс.

Если нажать Ctrl+C или Ctrl+Break, или нажать на крестик у консоли, она крешится, виндоуз предлагает искать ошибку в интернете и всё такое.
Чтобы такого не было, добавил обработчик сигналов SIGINT, SIGTERM, SIGBREAK, — он пишет сообщение на экран и в журнал и вызывает exit(1)

Добавляю #pragma omp parallel for...
Программа в некоторых случаях завершается по exit(1), как и ожидалось, а в некоторых — рабочие потоки omp продолжают работать! Естественно, очень быстро они приходят к расстрелу памяти и дохнут по защите памяти.

Заменил exit на abort() или terminate() — та же фигня, некоторые потки продолжают работать после сигнала, только теперь виндоуз гарантированно предлагает искать ошибку.

Вопрос: как грамотно и портабельно убивать программу с omp, — при том, что нет задачи аккуратно джойнить потоки. Просто чтобы она молча останавливалась.
Второй вопрос: как она вообще может работать после exit() ?!

Программа — числодробилка, она загружает здоровенные бинарные файлы (под сотню мегабайт), долго их обрабатывает и пишет результат в текстовый файл.
Т.е. каждый поток проходит по такому циклу:
— 100% загрузка кернелмода (выделяет память; читает файл)
— 100% загрузка юзермода (считает)
— выдох — синхронизируется для записи в текстовый файл

Попробовал сделать дистиллированный пример такого вида — проблема не воспроизводится.
#include <csignal>
#include <cstdlib>
#include <exception>
#include <iostream>
#include <cstdio>
#include <omp.h>
#include <chrono>
#include <thread>

using namespace std;


void halt_zuruck(int s)
{
    cerr << "halted with code " << s << " in thread " << omp_get_thread_num() << endl;
    exit(0);
}

char buf[1000000];


int main()
{
    signal(SIGINT,   halt_zuruck);
    signal(SIGTERM,  halt_zuruck);
    signal(SIGBREAK, halt_zuruck); // это чисто виндовское - Ctrl+Break

    cout << "go...";
    #pragma omp parallel
    {
        int n = omp_get_thread_num();
        int x = n+1;
        std::chrono::milliseconds dura( n==0 ? 5000 : 500 );
        while(true)
        {
            std::this_thread::sleep_for( dura );

            for(int i=0; i<10000*(n+1); ++i)
            {                
                FILE* f = fopen("x.cpp", "r"); // чтобы создать нагрузку на кернелмод
                fread(buf, 1, sizeof(buf), f);
                fclose(f);
            }
            
            for(int i=0; i<10000000; ++i)
                x = x%2 ? x*3+1 : x/2; // чтобы создать нагрузку на юзермод

            cout << n << " ";
        }
    }
}
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.