Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
433 views
in Technique[技术] by (71.8m points)

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

I have got a class named cApp.

I want to run CheckProcessList() in the background until the program terminates. So i thought, well, lets run it in a detached thread until ~cApp(). I made a bool to break out of the loop in CheckProcessList(). In ~cApp I set the bool true m_bTerminateThread = true to break out and wait for the promise m_barrierFuture->wait() that the thread has ended execution. After breaking out i set the promise barrier.set_value() that the thread is now ending execution. Now ~cApp can finish execution. Or at least that is my understanding of the things i want to achieve and how to do it. Well, can't be right since i get Compiler Errors.

Why did it want to check if the thread finished in the first place? Because the program breaks at runtime when it terminates and the thread is at that moment in GetProcId(). If it is sleeping in the moment of termination the program does not break.

I searched msdn and stackoverflow for answers but i do not get anything out of it that i can understand. I am using VS2019 and C++14. Thank you guys in advance.

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();
}

edit: The program terminates after ~cApp. Therefor i think that in this particular case i do not have to delete all of that memory because the os takes care of it.

edit2:

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

I don't know to which lines your errors pertains (you didn't show this) but I suspect at least above statement is wrong.

If you pass an address of a thread procedure to std::thread constructor and this procedure is a non-static member function the next argument after must be an address of the object you refer to (after all a non-static member function must have an instance that it is called on behalf of). std::promise is not a type which contains such a function pointer type &cApp::CheckProcessList so this cannot work.

If you want to associate that thread with the object that creates it typically such invocation looks like:

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

Or one can use either a static member function or a free function.


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

Another problem in your code is passing a promise object by value to the thread function. This means a local copy of the promise but promise is not copyable. You also can't pass it either by reference or by pointer! because barrier is a local variable of OnInit() method and as soon as that method finishes that variable gets destroyed anyway - the underlying detached thread will mess around with invalid stackframe or cause undefined behavior of any kind. Perhaps you could make the barrier a data member or rethink your design.

Be very cautious while dealing with detached threads. They are full of pitfalls when used improperly.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share

2.1m questions

2.1m answers

63 comments

56.6k users

...