【问题标题】:Self terminating thread. Use join or detach自终止线程。使用加入或分离
【发布时间】:2019-08-23 11:17:34
【问题描述】:

我有一个在 std::thread 中处理的状态机。该状态机初始化网络连接,处理数据,并在收到特定消息后,需要自行关闭。以这种方式使用 join 会触发“已调用 abort()”异常。这是适合分离线程的情况之一吗?

#include <iostream>

#include <thread>
#include <atomic>
#include <memory>

class ThreadExample
{
public:
    ThreadExample()
    {
        StartThread();
    }

    void StartThread()
    {
        //start thread;
        run_thread = true;
        the_thread = std::thread(&ThreadExample::ThreadFunction, this);
    }

    void ThreadFunction()
    {
        while (run_thread)
        {
            if (correct_message_found)
                ShutdownThread();
            else
                ProcessMessage();   //example code to imitate network processing

            //arbitrary wait. not relevant to the problem
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }

    //read in by some network connection
    void ProcessMessage(/*some message data*/)
    {
        static int counter = 0;
        if (counter == 3)
        {
            correct_message_found = true;
        }
        else
        {
            std::cout << "Waiting for the right message\n";
            counter++;
        }
    }

    void ShutdownThread()
    {
        run_thread = false;
        if (the_thread.joinable())
            the_thread.join();
    }

private:
    std::thread the_thread;
    std::atomic_bool run_thread;
    bool correct_message_found = false;
};

int main()
{
    auto example = std::make_unique<ThreadExample>();

    int data;
    std::cin >> data;
}

【问题讨论】:

  • 对不起,描述不够清楚。线程如何自行关闭?谁打电话给join?你会在哪里分离线程?线程的副作用是什么,为什么首先要线程?请务必创建您正在谈论的最小代表性示例,它会更清晰。您想回答的具体问题是什么?
  • 我会模拟一些东西。
  • 只要有人else记得join线程,你仍然可以随时退出线程(通过从线程主函数返回)。
  • 你不能加入一个线程本身。它必须由另一个线程完成。但是,只要不是线程本身破坏了对象,就不会禁止或禁止从析构函数中执行此操作。
  • 您的前两句话似乎毫无关联。 “以这种方式使用连接......”以什么方式?调用join 不会使线程终止,它只是让调用线程等待,直到另一个线程完成执行

标签: c++ multithreading join detach


【解决方案1】:

从内部终止线程的正确方法是简单地从线程正在执行的函数中返回:

void ThreadFunction()
{
    while (run_thread)
    {
        if (correct_message_found)
            return;
        else
            ProcessMessage();   //example code to imitate network processing

        //arbitrary wait. not relevant to the problem
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

从应该加入的线程中调用join是一个错误,请参阅第一个错误条件:https://en.cppreference.com/w/cpp/thread/thread/join

join 表示“等待给定线程完成,然后继续”。你是在告诉一个线程等到它自己完成。所以它只能在已经结束的时候结束,这显然是矛盾的。

应该调用join 的位置在ThreadExample 的析构函数中。 ThreadFunction 使用ThreadExample 的成员,而ThreadExample 也拥有std::thread 对象,因此不能允许ThreadExample 在线程仍在运行时死亡。在你展示的代码中,如果你在线程完成之前输入一些东西,你会遇到这个问题:ThreadExample 然后被销毁,std::thread 对象就在里面。如果 std::thread 在可连接时被销毁(即非分离线程仍在运行),则调用 std::terminate
https://en.cppreference.com/w/cpp/thread/thread/%7Ethread

【讨论】:

  • 谢谢。我在某处读到不建议在析构函数中调用 join ,所以我避免了这种情况。对于这样的例子,有没有更合适的模式?
  • 我还想添加 main 函数来显示真正调用 join 的位置。
  • @Jason 该建议来自哪里?你想避免在析构函数(std::thread::joinmight do)中抛出异常是正确的,但你可以抓住那个。
  • @Jason 我不明白这与在析构函数中调用join 有何关系,除了我提供的确切建议:销毁既未加入也未分离的std::thread 是不好的。
猜你喜欢
  • 1970-01-01
  • 2012-03-20
  • 1970-01-01
  • 1970-01-01
  • 2021-02-14
  • 2021-04-06
  • 2017-10-27
  • 1970-01-01
  • 2022-10-23
相关资源
最近更新 更多