注入 C++另一个线程中的异常

发布于 2024-10-06 23:03:55 字数 610 浏览 1 评论 0原文

利用Exception_ptr 的C++0x 功能,我们可以在一个线程中存储异常并让另一个线程访问它。然而,另一个线程必须调用rethrow_exception()。然而,在某些情况下,我需要实际中断另一个线程并立即引发异常;轮询异常指针是否为非空不是解决方案。

我在 http://www.codeproject 找到了如何在 Windows 中注入异常的解决方案。 com/KB/exception/ExcInject.aspx 通过挂起线程并在恢复之前修改其指令指针寄存器。但是,我还需要我的代码在 Linux 上运行。我如何在那里实现它?

如果我使用像 getcontext() 这样的东西,它会获取当前线程的上下文(而在 Windows 中,GetContext() 接受线程参数),所以我必须在信号处理程序中调用它。但我读到 getcontext()/setcontext() 不应在信号处理程序中调用... 或者,我可以直接在信号处理程序中调用 rethrow_exception() ,但我担心这不会产生预期的效果,其中被中断的线程以与中断所在范围的所有析构函数相同的方式展开堆栈称为等

With the C++0x feature of exception_ptr one can store an exception in one thread and have another thread access it. However, the other thread has to call rethrow_exception(). In some cases, however, I need to actually interrupt the other thread and have the exception be raised there immediately; polling the exception_ptr for non-null is not a solution.

I found a solution for how to inject an exception in Windows at http://www.codeproject.com/KB/exception/ExcInject.aspx by suspending a thread and modifying its instruction pointer register before resuming it. However, I also need my code to run on Linux. How do I accomplish it there?

If I use something like getcontext(), that gets the current thread's context (whereas in Windows, GetContext() accepts a thread parameter), so I would have to call it in a signal handler. But I've read that getcontext()/setcontext() should not be called in signal handlers...
Alternatively, I could call rethrow_exception() directly in the signal handler, but I'm worried this won't have the intended effect, where the interrupted thread has the stack unwound in the same way with all destructors of the scope the interruption was in called etc.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

玩物 2024-10-13 23:03:55

我或多或少地问了同样的问题。一段时间后我找到了一个很好的答案。代码如下,更多评论可以看我的回答:

#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();
}

I asked more or less the same question here. After some time I found a good answer. Here is the code, you can find more comments in my answer:

#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();
}
听,心雨的声音 2024-10-13 23:03:55

我前段时间读过您链接的那篇文章,我有点怀疑。

直接修改另一个线程的指令指针的做法感觉很可怕。您完全不知道您正在中断哪个操作并使其完成一半,并且被中断的操作可能不会期待异常,因此无法自行清理。

在 Windows 上,我已成功使用 QueueUserAPC一旦其他线程进入可警报等待状态就中止它们。我不知道 Linux 中有任何直接等效的东西。

I read that article you linked to some time ago, and I was a bit skeptical.

The approach of modifying another thread's instruction pointer directly feels VERY scary. You have absolutely no idea what operation you're interrupting and leaving half-completed, and the interrupted operation may not be expecting an exception and thus have no ability to clean up after itself.

On Windows, I've used QueueUserAPC successfully to abort other threads once they enter an alertable wait state. I don't know of any direct equivalent for this in Linux.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文