C++线程加入后无法中止

C++ thread can't abort after being joined

所以我的程序中有 2 个线程 运行ning,我最终希望它们在调用此函数时终止:

void AutoClicker::TerminateThreads()
{
    programrunning = false;
    clicker.join();
    hotkeyLoop.join();
    terminateThread = true;
}

然后调用线程应该运行这个代码:

while (1)
{
    while (programrunning)
    {
        mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
        mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
        std::this_thread::sleep_for(std::chrono::milliseconds(delay));
    }

    if (terminateThread) {
        std::terminate();
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
}

但是最后的if语句似乎没有被调用。它位于我试图终止的线程内,所以它应该可以正常工作吗?我对线程很陌生,所以我真的不知道该怎么做,但这是我在网上找到的:

"When a std::thread object gets destroyed it is not allowed to be joinable(), i.e., one of two things have to happen before it is destroyed:

It was detached and the thread has gone into the wild and there is pretty much no control over whether it has finished or not.

The thread has been join()ed."

您实际上并没有这里的所有代码,但我猜唱首歌线程中的方法可能看起来像

void clickerThreadFunction()
{
  while(programrunning)
  {
    // do stuff
  }

  if (terminateThread)
  {
    std::terminate();
  }
}

如果是这样的话,再看代码

programrunning = false;
clicker.join();

第一行将导致答题器线程中的 while 循环退出。 clicker 方法的其余部分将 运行,包括 if (terminateThread) 检查,这将失败,因为您尚未将 terminateThread 设置为 true。只有这样,一旦我们触及 clickerThreadFunction 的底部,就会 clicker.join() return,因为 std::thread::join 等待线程完成然后 return 控制.

不管怎样,我不清楚你想在这里做什么。 std::terminate 的目的是让程序立即崩溃。如果您希望发生这种情况,则不清楚您为什么要费心加入线程,因为无论如何您都不会到达那部分。

你知道join是做什么的吗? join 等待线程完成。

您的 TerminateThreads 函数将程序 运行 设置为 false,然后等待线程完成,然后将 terminateThread 设置为 true。

线程保持 运行 直到 terminateThread 变为 true,因此当调用 TerminateThreads 函数时,它永远不会到达将 terminateThread 设置为 true 的部分,因为它正在等待线程完成。

从两件事开始:

  • 请勿拨打std::terminate()。这不是拆除程序的好方法,可能会使打开的文件和其他 OS 资源挂起。此外,它适用于您的整个程序,而不仅仅是您调用它的线程。
  • 如果你想让一个std::thread终止,那么就从它return开始或者让它到达线程函数的末尾。

除此之外,这是一个小程序,展示了我将如何做你描述的事情:

#include <iostream>
#include <atomic>
#include <chrono>
#include <thread>

void threadfunc(std::atomic<bool>& running)
{
    while (running) {
        std::cout << "beep\n";
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

void waitThread(std::atomic<bool>& running)
{
    std::this_thread::sleep_for(std::chrono::seconds(10));
    running = false;
}

int main()
{
    std::atomic<bool> running = true;

    std::thread t1(threadfunc, std::ref(running));
    std::thread t2(waitThread, std::ref(running));
    t1.join();
    t2.join();
}

希望您能在此处清除一些内容以使您的程序正常运行。

编辑: 澄清 OP 对另一个答案的评论中的一些内容:

类似于:std::thread t1(threadfunc, std::ref(running)); 创建一个活动线程来执行提供的函数。一旦该函数停止(returns),线程将处于僵尸状态,它不会执行但仍处于活动状态并持有资源。

https://en.cppreference.com/w/cpp/thread/thread/joinable

A thread that has finished executing code, but has not yet been joined is still considered an active thread of execution and is therefore joinable.

为了将线程拉出僵尸状态并清理其资源,您必须对其调用join()。请注意,您可以在该线程完成执行之前或之后调用 join() - 如果您之前加入,您将阻塞直到加入的线程完成,如果您之后加入,则会清理挥之不去的线程并立即继续。

或者,您可以在线程上调用 detach()

https://en.cppreference.com/w/cpp/thread/thread/detach

Separates the thread of execution from the thread object, allowing execution to continue independently. Any allocated resources will be freed once the thread exits.

但是一旦你分离了一个线程,你就不能再加入它,并且让你的主线程在仍然存在但分离的线程时退出 运行 以一种不太好的方式杀死分离的线程.因此,仅当您确定分离线程将在主线程之前完成时才这样做。