【问题标题】:c++ allow background thread to finish before exiting applicationc ++允许后台线程在退出应用程序之前完成
【发布时间】:2016-05-10 07:12:10
【问题描述】:

c++ win 32 应用程序。对比 2013 我正在使用第 3 方库。 我想在后台线程中调用 3rd 方库的函数。 然后我也想最终将其关闭。 我怀疑在我存在应用程序之前我没有给第三方足够的时间来正确关闭自己。 如何确保在退出 main() 之前完成在单独线程上启动的分离任务。

//this class interfaces with the third part and runs on a separate thread
class ThirdParty
{

    void Start(std::string filename)
    {
        MyApplication application;
        FIX::SessionSettings settings(filename);
        FIX::FileStoreFactory storeFactory(settings);
        FIX::ScreenLogFactory logFactory(settings);
        FIX::SocketAcceptor acceptor(application, storeFactory, settings, logFactory);
        acceptor.start(); //this third party internally starts new threads and does stuff thats transparent to consumer like myself.
        while (m_runEngine) 
                {}


//this shutsdown a few things and cant execute instantaneously
//This does not finish execution and main() already ends.
        acceptor.stop();
    }
    void Stop()
    {
        m_runEngine = false;
    }
private:
bool m_runEngine{ true };

}

这是我在 win32 应用程序中的 main()

int _tmain(int argc, _TCHAR* argv[])
{
    std::wstring arg = argv[1];
    std::string filename = std::string(arg.begin(), arg.end());
    ThirdParty myprocess;

    std::thread t(&ThirdParty::Start, &myprocess, filename);

    t.detach();

    while (true)
    {
        std::string value;
        std::cin >> value;
        if (value == "quit")
            break;
    }

    myprocess.Stop(); //This line will execute really fast and application will exit without allowing acceptor.stop() to properly finish execution
//How can I ensure acceptor.stop() has finished execution before I move on to the next line and finish the application  

    return 0;
}

【问题讨论】:

  • 不要分离你的线程。相反,让它可以加入并在退出之前加入。更好的是,由于您在 Windows 上,因此获取本机线程句柄,在有意义的超时情况下等待其上的事件,并在触发事件时加入。否则只报错退出。
  • 我明白了。所以我调用 t.joinable() 而不是 t.detach(),然后最后在 myprocess.stop() 之后调用 t.join()?这似乎在我的调试器中有效。我也会尝试其他选项。
  • 不需要调用 t.joinable(),你知道它是可加入的。本机连接的问题在于,如果您的线程没有响应(陷入循环、锁定资源等),您的应用程序也会被卡住。这就是为什么值得给它一些时间来关闭它,但如果它不能,你就强行退出(有错误)。
  • 不相关,但是有没有办法可以在主控制台窗口上显示来自同一解决方案的另一个项目中可能运行的另一个线程的消息?更新状态等
  • 您应该能够简单地打印它们吗?抱歉,我对 Windows 不太熟悉。

标签: c++ multithreading


【解决方案1】:

不要让你的线程分离,这样你就可以使用thread::join()等待它结束:

//t.detach()   do not detach thread
...
myprocess.Stop();
t.join();    // wait for t to end

【讨论】:

  • 虽然谢尔盖先回答了,但我只能点赞评论,所以我会检查你的正确答案作为答案。
  • 我相信 Sergey 既不会怪我也不会怪你 :)
  • 除非您将 m_runEngine 设为 std::atomic,或使用互斥锁保护它,否则实际上无法保证它会被读取。编译器可以随意查看该代码并说“哦...在此循环中此变量无法更改 - 优化为 while(true) {}”。 std::atomic 基本上意味着变量总是从内存位置读取,互斥量更重,但可能更接近人们期望读取的内容。
  • @Charlie:你说得对,我错过了这一点;会让m_runEngine volatile 成为 std::atomic 的可接受替代品吗?
  • @shrike volatile 在这种情况下并不能完全满足您的要求。从技术上讲,这将是未定义的行为,因为 volatile 仅对单个线程中的优化器产生影响。它不适用于两个线程之间的通信。 (通常,除非您正在编写设备驱动程序,否则volatile 可能不是您想要的。)
【解决方案2】:

我认为以下示例说明了线程连接的有趣方面。

void pause_thread(int n, std::string lbl)
{
  std::this_thread::sleep_for (std::chrono::seconds(n));
  std::cout << lbl << " pause of " << n << " seconds ended" << std::endl;
}

int t403(void)  // in context of thread main
{
   std::cout << "Spawning 3 threads...\n" << std::flush;
   std::thread t1 (pause_thread, 3, "t1");
   std::thread t2 (pause_thread, 2, "t2");
   std::thread t3 (pause_thread, 1, "t3");
   std::cout << "Done spawning threads, "
      "Note that the threads finish out-of-order. \n"
      "Now 'main' thread waits for spawned threads to join:\n" << std::flush;

   t1.join(); std::cout << "join t1  " << std::flush;
   t2.join(); std::cout << "join t2  " << std::flush;
   t3.join(); std::cout << "join t3  " << std::flush;
   std::cout << "completed join \n"
      "note: \n - join sequence is in-order, but finish sequence is out-of-order\n"
      " - inference:  the threads waited in join main. "<< std::endl;

   return(0);
}

注意线程是按顺序产生的:t1、t2、t3。

请注意,线程以不同的顺序结束。

但加入仍处于启动顺序中,因为这是 main 等待的。

使用 'std::flush()' 呈现已选择的时间线,该时间线已被选择得足够慢以供人类视觉使用。

【讨论】:

  • Linux 示例
猜你喜欢
  • 1970-01-01
  • 2012-11-20
  • 2018-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多