Внедрение исключения C ++ в другой поток - PullRequest
5 голосов
/ 11 декабря 2010

С помощью функции C ++ 0x в exception_ptr можно сохранить исключение в одном потоке и получить доступ к нему другого потока.Однако другой поток должен вызвать rethrow_exception ().Однако в некоторых случаях мне нужно фактически прервать другой поток и немедленно вызвать исключение;опрос исключений_ptr для ненулевого значения не является решением.

Я нашел решение о том, как внедрить исключение в Windows на http://www.codeproject.com/KB/exception/ExcInject.aspx, приостановив поток и изменив его регистр указателя инструкций перед его возобновлением.,Однако мне также нужен мой код для запуска в Linux.Как мне сделать это там?

Если я использую что-то вроде getcontext (), это получает контекст текущего потока (тогда как в Windows, GetContext () принимает параметр потока), поэтому я должен вызвать его вобработчик сигнала.Но я читал, что getcontext () / setcontext () не должен вызываться в обработчиках сигналов ... В качестве альтернативы я мог бы вызвать rethrow_exception () непосредственно в обработчике сигналов, но я боюсь, что это не будет иметь ожидаемого эффектагде в прерванном потоке стек разматывается одинаково со всеми деструкторами области, в которой было вызвано прерывание и т. д.

Ответы [ 2 ]

3 голосов
/ 28 августа 2015

Я задавал более или менее тот же вопрос здесь . Через некоторое время я нашел хороший ответ. Вот код, вы можете найти больше комментариев в моем ответе:

#include <thread>
#include <signal.h>
#include <unistd.h>
#include <iostream>

using namespace std;

//Custom exception which is used to stop the thread
class StopException {};

void sig_fun(int s)
{
    if(s == SIGUSR2)throw StopException();
}

void threadFunction()
{
    cout<<"Thread started"<<endl;
    try {
        while(true)
        {
            //Work forever...
            sleep(1);
        }
    } catch(const StopException &e) {
        cout<<"Thread interrupted"<<endl;
    }
    cout<<"Thread stopped"<<endl;
}

int main(int argc, char *args[])
{
    //Install Signal handler function
    signal(SIGUSR2, sig_fun);
    pthread_t threadObject;
    thread t([&threadObject]()
    {
        //Store pthread_t object to be able to use it later
        threadObject = pthread_self();
        threadFunction();
    });

    string temp;
    cout<<"Write something when you want the thread to be killed"<<endl;
    cin>>temp;

    //Send Signal to thread
    pthread_kill(threadObject, SIGUSR2);
    t.join();
}
2 голосов
/ 11 декабря 2010

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

Подход к изменению указателя инструкций другого потока напрямую кажется ОЧЕНЬ страшным. Вы абсолютно не представляете, какую операцию вы прерываете и оставляете наполовину завершенной, и прерванная операция, возможно, не ожидает исключения и, следовательно, не имеет возможности убирать за собой.

В Windows я успешно использовал QueueUserAPC , чтобы прервать другие потоки, когда они переходят в состояние ожидания с оповещением. Я не знаю ни одного прямого эквивалента этого в Linux.

...