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



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

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语句似乎没有被调用。它位于线程内,我试图终止,所以它应该只是工作正确吗?我是很新的线程,所以我真的不知道如何做到这一点,但这是我在网上发现的:

"当一个std::thread对象被销毁时,它不允许是可接合的(),也就是说,在它被销毁之前必须发生两件事之一:

它已被分离,线程已进入野外,几乎无法控制它是否已完成。

线程已被join()编辑。">

从两件事开始:

  • 不调用std::terminate()。这不是一种拆除程序的好方法,可能会使打开的文件和其他操作系统资源挂起。而且,它适用于整个程序,而不仅仅是调用它的线程。
  • 如果你想要一个std::thread终止,那么就从它返回或允许它到达线程函数的结束。

有了这些,下面是一个小程序,展示了我将如何做你所描述的事情:

#include <iostream>
#include <atomic>
#include <chrono>
#include <thread>
void threadfunc(std::atomic<bool>& running)
{
while (running) {
std::cout << "beepn";
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));

创建一个活动线程来执行提供的函数。一旦该函数停止(返回),线程就处于僵尸状态,即它不执行,但仍处于活动状态并持有资源。 https://en.cppreference.com/w/cpp/thread/thread/joinable

已完成执行代码,但尚未加入的线程仍然被认为是活动的执行线程,因此是可接合的。

为了使线程脱离这种僵尸状态并清理其资源,您必须对其调用join()。请注意,您可以在该线程完成执行之前或之后调用join()-如果您在之前加入,则阻塞直到加入的线程完成,如果您在之后加入,则残留的线程被清理并立即继续。

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

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

将执行线程从线程对象中分离出来,允许继续独立执行。任何分配的资源都将被线程退出后释放。

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

这里没有所有的代码,但我猜clicker线程中的方法可能看起来像

void clickerThreadFunction()
{
while(programrunning)
{
// do stuff
}
if (terminateThread)
{
std::terminate();
}
}

如果是这种情况,那么查看代码

programrunning = false;
clicker.join();

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

不管怎样,我不清楚你在这里想做什么。std::terminate的目的是立即使程序崩溃。如果你想这样做,你就不清楚为什么要费心去连接线程,因为无论如何你都不会到达那个部分。

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

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

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

最新更新