Внедрить исключение времени выполнения в pthread иногда не удается. Как это исправить? - PullRequest
1 голос
/ 23 апреля 2010

Я пытаюсь внедрить исключение в поток, используя сигналы, но иногда исключение не ловится.Например, следующий код:

void _sigthrow(int sig)
{
    throw runtime_error(strsignal(sig));
}
struct sigaction sigthrow = {{&_sigthrow}};

void* thread1(void*)
{
    sigaction(SIGINT,&sigthrow,NULL);
    try
    {
        while(1) usleep(1);
    }
    catch(exception &e)
    {
        cerr << "Thread1 catched " << e.what() << endl;
    }
};

void* thread2(void*)
{
    sigaction(SIGINT,&sigthrow,NULL);
    try
    {
        while(1);
    }
    catch(exception &e)
    {
        cerr << "Thread2 catched " << e.what() << endl; //never goes here
    }
};

Если я попытаюсь выполнить как:

int main()
{
    pthread_t p1,p2;

    pthread_create( &p1, NULL, &thread1, NULL );
    pthread_create( &p2, NULL, &thread2, NULL );

    sleep(1);

    pthread_kill( p1, SIGINT);
    pthread_kill( p2, SIGINT);

    sleep(1);

    return EXIT_SUCCESS;
}

Я получу следующий вывод:

Thread1 catched Interrupt
terminate called after throwing an instance of 'std::runtime_error'
  what():  Interrupt
Aborted

Как я могуисключение второй угрозы?Есть ли лучшая идея о введении исключений?

Ответы [ 2 ]

2 голосов
/ 23 апреля 2010

G ++ предполагает, что исключения могут создаваться только при вызовах функций. Если вы собираетесь нарушить это предположение (например, выбрасывая их из обработчиков сигналов), вам нужно передать -fnon-call-exceptions в G ++ при сборке вашей программы.

Обратите внимание, однако, что это заставляет G ++:

 Generate code that allows trapping instructions to throw
 exceptions.  Note that this requires platform-specific runtime
 support that does not exist everywhere.  Moreover, it only allows
 _trapping_ instructions to throw exceptions, i.e. memory
 references or floating point instructions.  It does not allow
 exceptions to be thrown from arbitrary signal handlers such as
 `SIGALRM'.

Это означает, что исключение из середины некоторого случайного кода НИКОГДА не безопасно. Вы можете только исключить из SIGSEGV, SIGBUS и SIGFPE, и только если вы передаете -fnon-call-exceptions, и они были вызваны из-за ошибки в работающем коде. Единственная причина, по которой это сработало в потоке 1, заключается в том, что из-за существования вызова usleep() G ++ был вынужден предположить, что он может выдать. В потоке 2 G ++ видит, что команды перехвата не было, и устраняет блок try-catch.

Вы можете найти поддержку отмены pthread более похожей на то, что вам нужно, или просто добавить где-нибудь такой тест:

if (*(volatile int *)terminate_flag) throw terminate_exception();
1 голос
/ 23 апреля 2010

В Boost.thread поток может быть прерван путем вызова функции-члена interrupt () соответствующего объекта boost :: thread. Он использует переменные условия pthread для связи с потоком и позволяет вам определять точки прерывания в коде потока. Я бы избегал использования pthread_kill в C ++. Я думаю, это подтверждает тот факт, что поток поддержки нигде не использует pthread_kill в своем коде.

...