使用未来、承诺、分离线程时出现 C++ 错误 C2893、C2780、C2672

C++ Errors C2893, C2780, C2672 when using future, promise, detached thread

我有一个名为 cApp 的 class。

我想在后台 运行 CheckProcessList() 直到程序终止。所以我想,好吧,让 运行 它在一个分离的线程中,直到 ~cApp()。我做了一个 bool 来跳出 CheckProcessList() 中的循环。在 ~cApp 中,我将 bool true m_bTerminateThread = true 设置为 break 并等待线程已结束执行的承诺 m_barrierFuture->wait()。爆发后,我设定了线程现在结束执行的承诺 barrier.set_value()。现在~cApp可以完成执行了。或者至少这是我对我想要实现的目标以及如何实现的理解。好吧,不可能是对的,因为我收到编译器错误。

为什么首先要检查线程是否完成?因为程序在 运行 终止时中断,并且线程在 GetProcId() 的那一刻。如果程序在终止时正在休眠,则程序不会中断。

我在 msdn 和 Whosebug 上搜索了答案,但我没有从中得到任何我能理解的东西。我正在使用 VS2019 和 C++14。提前谢谢大家。

cApp.h

#pragma once
#include "wx/wx.h"
#include "cMain.h"
#include <thread>
#include <future>

class cApp
    : public wxApp
{
public:
    cApp();
    ~cApp();

    virtual bool OnInit();

private:
    // supposed to run in a detached thread
    // until the program terminates
    void CheckProcessList(std::promise<void> barrier);

    // Checks whether or not the game processes are running
    // this thread runs asynchronous until ~cApp
    std::thread* m_tCheckProcList;
    // used in thread "m_tCheckProcList"
    // if set to true the thread terminates asap
    bool m_bTerminateThread;
    // used in thread "m_tCheckProcList"
    // in ~cApp this future waits for the promise that the thread has finished
    std::future<void>* m_barrierFuture;

    // Dark Souls 3 Processname
    const wchar_t* m_ds3Name;
    // Need for Speed: Most Wanted Processname
    const wchar_t* m_nfsmwName;
    // Serious Sam: The Second Encounter Processname
    const wchar_t* m_sstseName;

    const wxString* m_frameTitle;
    const wxSize* m_frameSize;

    cMain* m_mainFrame;
};

cApp.cpp

#include "cApp.h"

wxIMPLEMENT_APP(cApp);

cApp::cApp()
{
    m_ds3Name = L"DarkSoulsIII.exe";
    m_sstseName = L"SeriousSam.exe";
    m_nfsmwName = L"speed.exe";
    m_frameTitle = new wxString("DeltaWin");
    m_frameSize = new wxSize(600, 450);
    m_bTerminateThread = false;
    m_mainFrame = nullptr;
    m_tCheckProcList = nullptr;
    m_barrierFuture = nullptr;
}

cApp::~cApp()
{
    // send the thread the "signal" to finish asap
    m_bTerminateThread = true;
    // wait for thread "m_tCheckProcList" to finish execution
    m_barrierFuture->wait();
}

bool cApp::OnInit()
{
    // create main top-level window
    m_mainFrame = new cMain(*m_frameTitle, wxDefaultPosition, *m_frameSize);
    m_mainFrame->Show();

    // create barrier and instantiate the future for it
    std::promise<void> barrier;
    m_barrierFuture = new std::future<void>(barrier.get_future());

    // start checking for running game processes in asynchronous thread
    m_tCheckProcList = new std::thread(&cApp::CheckProcessList, std::move(barrier));
    m_tCheckProcList->detach();

    return true;
}

void cApp::CheckProcessList(std::promise<void> barrier)
{   
    while (!m_bTerminateThread)
    {
        // Dark Souls 3
        if (GetProcId(m_ds3Name) == 0)
            m_mainFrame->MenuItemEnable(false, menuItem::DarkSouls3);
        else
            m_mainFrame->MenuItemEnable(true, menuItem::DarkSouls3);

        // Need for Speed: Most Wanted
        if (GetProcId(m_nfsmwName) == 0)
            m_mainFrame->MenuItemEnable(false, menuItem::NFSMostWanted);
        else
            m_mainFrame->MenuItemEnable(true, menuItem::NFSMostWanted);

        // Serious Sam: The Second Encounter
        if (GetProcId(m_sstseName) == 0)
            m_mainFrame->MenuItemEnable(false, menuItem::SeriousSamTSE);
        else
            m_mainFrame->MenuItemEnable(true, menuItem::SeriousSamTSE);

        // Sleep 1.5s to save resources
        std::this_thread::sleep_for(std::chrono::milliseconds(1500));
    }
    // set the promise that the thread has ended execution
    barrier.set_value();
}

编辑: 程序在 ~cApp 后终止。因此,我认为在这种特殊情况下,我不必 delete 所有这些内存,因为 os 会处理它。

编辑2:

C2893: Failed to specialize function template "unknown-type std::invoke(_Callable &&,_Ty1 &&,_Types2 &&...) noexcept()".

C2780: "unknown-type std::invoke(_Callable &&) noexcept()": expects 1 arguments - 2 provided

C2672: "invoke": no matching overloaded function found

m_tCheckProcList = new std::thread(&cApp::CheckProcessList, std::move(barrier));

我不知道你的错误属于哪一行(你没有显示)但我怀疑至少上面的说法是错误的。

如果您将线程过程的地址传递给 std::thread 构造函数并且此过程是非静态成员函数,则后面的下一个参数必须是您引用的对象的地址(毕竟是非-static 成员函数必须有一个 instance 代表调用它)。 std::promise 不是包含此类函数指针类型的类型 &cApp::CheckProcessList 因此这无法工作。

如果您想将该线程与创建它的对象相关联,通常此类调用如下所示:

std::thread(&cApp::CheckProcessList, this, ...

或者可以使用静态成员函数或自由函数。


cApp::CheckProcessList(std::promise<void> barrier)

代码中的另一个问题是将 promise 对象按值 传递给线程函数。这意味着承诺的本地副本,但承诺不可复制。 您也不能通过引用或指针传递它!因为 barrierOnInit() 方法的局部变量,一旦该方法完成该变量就会被销毁 - 底层分离线程将乱用无效的堆栈帧或导致 未定义的行为 任何一种。也许您可以使 barrier 成为数据成员或重新考虑您的设计。

处理分离线程时要非常小心。如果使用不当,它们充满了陷阱。