1

Using information here:How to check if a thread is still running I'm trying to use a lambda function in a std::future to call a class member function in a dedicated thread so that the std::future may be monitored for the completion status of the thread using future.wait_for()

The TestClass creates a std::future & starts a thread in its constructor. The intention is to allow other member functions to monitor progress and terminate that thread when necessary.

#include <future>
#include <thread>
#include <chrono>
#include <iostream>
#include <atomic>
#include <functional>

class TestClass
{
public:
TestClass(const int &np) : nap(np), run(true)
{       
    //Run member function in a thread, crucially be able to monitor the  thread status using the future;
    function = std::bind(&TestClass::Snooze, this, std::placeholders::_1, std::placeholders::_2);
    future = std::async(std::launch::async, [this] {
        function(nap, &run);
        return true;
    });

}


~TestClass()
{
//If future thread is still executing then terminate it by setting run = false
//Use wait_for() with zero milliseconds to check thread status.
auto status = future.wait_for(std::chrono::milliseconds(1));//needs to have a value > 0
if (status != std::future_status::ready)//execution not complete
{
    run = false;//terminate Snooze
    future.wait();//wait for execution to complete
}
std::cout << "TestClass: Destructor Completed" << std::endl;
}

void Snooze(const int &napLen, std::atomic<bool>* ptrRun)
{
while (*ptrRun)//check ok to to loop on.
{
std::cout << "zzzz...." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(napLen));//take a nap
}
std::cout << "TestClass: Finished Snoozing." << std::endl;
}

//Getter
bool isThreadFinished() const
{
auto status = future.wait_for(std::chrono::milliseconds(0));
if (status == std::future_status::ready)//execution complete
{
    return true;
}
else
{ 
    return false;
}   
}

//Setter
void stopSnooze()
{
run = false;
std::cout << "TestClass: stopSnooze(): run = " << run << std::endl;
}

private:
int nap;
std::function<void(int, std::atomic<bool>*)> function;
std::future<bool> future;
std::atomic<bool> run;
};



int main() {    

TestClass tc(1);//should see some zzzz's here
std::this_thread::sleep_for(std::chrono::seconds(5));

tc.stopSnooze();//demonstrate stopping the thread by setting run = false

std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "TestClass: Next test." << std::endl;

TestClass tc1(1);//should see some zzzz's here
std::this_thread::sleep_for(std::chrono::seconds(5));
}

EDIT: Corrected code to function as intended.

Community
  • 1
  • 1
GoFaster
  • 835
  • 1
  • 12
  • 23
  • Destroying an automatic object (`tc` in `main`) before the end of its scope does not prevent it being destroyed again at the end of the scope, which of course results in undefined behavior. It's also a bit odd - though not incorrect - that you are passing parameters to `Snooze` when it could simply retrieve them from the object. – Casey Jan 26 '15 at 20:29

1 Answers1

2

I voted this as a duplicate, but really you just have a typo:

auto function = std::bind(&TestClass::Snooze, this, nap, &run);
auto future = std::async(std::launch::async, [&function]{
    function();
    return true;
}); 

Should be:

function = std::bind(&TestClass::Snooze, this, nap, &run);
future = std::async(std::launch::async, [this] {
    function();
    return true;
}); 

You want to assign to your members, not create temporaries. As-is, your constructor is blocking on the future destructor.

Community
  • 1
  • 1
Barry
  • 286,269
  • 29
  • 621
  • 977
  • Tried your modification but the intellisense doesn't like: future = std::async(std::launch::async, [this] { `function()`; return true; }); Am using Visual Studio 2013. – GoFaster Jan 26 '15 at 21:02
  • @GoFaster In the future, "doesn't like it" isn't meaningful info. You should provide what the actual error is. In this case, you need to pass in `nap` and `&run` to `function();`. – Barry Jan 26 '15 at 21:06