如何在完成之前过早地杀死std :: async线程*没有*使用std :: atomic_bool?

时间:2017-10-16 03:08:53

标签: multithreading c++11 stdasync

我有一个接受回调的函数,并用它来处理10个独立的线程。但是,通常情况下并非所有工作都需要。例如,如果在第三个线程上获得了所需的结果,则应该停止对剩余的活动线程进行的所有工作。

这个答案here表明,除非你让回调函数采用一个额外的class User < ApplicationRecord after_create :create_mission private def create_mission Mission.create(user: self, location_id: 1, name: 'Mission 1') end end 参数,否则它是不可能的,它会指示函数是否应该提前终止。

此解决方案对我不起作用。工作者在基类中旋转,这个基类的重点是抽象出多线程的细节。我怎样才能做到这一点?我期待着我将不得不放弃std::atomic_bool更多参与的事情。

std::async

1 个答案:

答案 0 :(得分:0)

我只是说这可能不应该是'正常'程序的一部分,因为它可能泄漏资源和/或让你的程序处于不稳定的状态,但为了科学的利益......

如果您控制了线程循环,并且不介意使用平台功能,则可以inject an exception进入该线程。使用posix,你可以使用信号,在Windows上你必须使用SetThreadContext()。虽然异常通常会解除堆栈并调用析构函数,但是当发生异常时,您的线程可能处于系统调用或其他“非异常安全位置”。

免责声明:目前我只有Linux,所以我没有测试Windows代码。

#if defined(_WIN32)
#   define ITS_WINDOWS
#else
#   define ITS_POSIX
#endif


#if defined(ITS_POSIX)
#include <signal.h>
#endif

void throw_exception() throw(std::string())
{
    throw std::string();
}

void init_exceptions()
{
    volatile int i = 0;
    if (i)
        throw_exception();
}

bool abort_thread(std::thread &t)
{

#if defined(ITS_WINDOWS)

    bool bSuccess = false;
    HANDLE h = t.native_handle();
    if (INVALID_HANDLE_VALUE == h)
        return false;

    if (INFINITE == SuspendThread(h))
        return false;

    CONTEXT ctx;
    ctx.ContextFlags = CONTEXT_CONTROL;
    if (GetThreadContext(h, &ctx))
    {
#if defined( _WIN64 )
        ctx.Rip = (DWORD)(DWORD_PTR)throw_exception;
#else
        ctx.Eip = (DWORD)(DWORD_PTR)throw_exception;
#endif

        bSuccess = SetThreadContext(h, &ctx) ? true : false;
    }

    ResumeThread(h);

    return bSuccess;

#elif defined(ITS_POSIX)

    pthread_kill(t.native_handle(), SIGUSR2);

#endif

    return false;
}


#if defined(ITS_POSIX)

void worker_thread_sig(int sig)
{
    if(SIGUSR2 == sig)
        throw std::string();
}

#endif

void init_threads()
{
#if defined(ITS_POSIX)

    struct sigaction sa;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = worker_thread_sig;
    sigaction(SIGUSR2, &sa, 0);

#endif
}

class tracker
{
public:
    tracker() { printf("tracker()\n"); }
    ~tracker() { printf("~tracker()\n"); }
};

int main(int argc, char *argv[])
{
    init_threads();

    printf("main: starting thread...\n");
    std::thread t([]()
    {
        try
        {
            tracker a;

            init_exceptions();

            printf("thread: started...\n");
            std::this_thread::sleep_for(std::chrono::minutes(1000));
            printf("thread: stopping...\n");
        }
        catch(std::string s)
        {
            printf("thread: exception caught...\n");
        }
    });

    printf("main: sleeping...\n");
    std::this_thread::sleep_for(std::chrono::seconds(2));

    printf("main: aborting...\n");
    abort_thread(t);

    printf("main: joining...\n");
    t.join();

    printf("main: exiting...\n");

    return 0;
}

<强>输出:

main: starting thread...
main: sleeping...
tracker()
thread: started...
main: aborting...
main: joining...
~tracker()
thread: exception caught...
main: exiting...