1

As the code below shows, I am trying to implement my own thread class by passing in a packaged_task. I then wait on the future from this packaged_task. I expect this code to wait 4 seconds and then I can get 0xcdcdcdcd from the future.

#include <iostream>
#include <future>

using namespace std;

class mythread {
public:
    thread internal_thread;
    template <typename _Fn> mythread(_Fn f) {
        internal_thread = thread([&f] {
            try {
                f();
            }
            catch (std::exception& e) {
                this_thread::sleep_for(chrono::seconds(4));
                std::cout << e.what() << std::endl;
            }
        });
    }
};

int work() {
    this_thread::sleep_for(chrono::milliseconds(2000));
    return 0xcdcdcdcd;
}

int main() {
    packaged_task<int()> task(work);
    future<int> ftr = task.get_future();
    mythread thrd(move(task));

    ftr.wait();
    cout << "Got it!!" << endl;
    try {
        cout << ftr.get() << endl;
    }
    catch (future_error &e) {
        std::cout << "outer " << e.code() << e.what() << std::endl;
    }
    cout << "Ended" << endl;
    getchar();
}

But the wait seems to terminate this task immediately. By compiling executing this code, it immediately prints out

Got it!!
outer future:4unspecified future_errc value

Ended

The environment is OS X 10.11.1,

$ g++ -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin15.0.0
Thread model: posix

The compiling command is

g++ --std=c++11 main.cpp && ./a.out

I'm not sure if it reproduces on other platforms.

Thanks in advance.

Edit

Solved: It is because the constructor of mythread now takes control of the life time of f moved in, whose reference is used by the thread. But the constructor returns immediately after creating the thread, thus destroying every local variables, including f, while the thread is still holding that destroyed local variable.

The corrected code is

class mythread {
public:
    thread internal_thread;
    template <typename _Fn> mythread(_Fn f) {
        internal_thread = thread([] (_Fn f) {
            try {
                f();
            }
            catch (std::exception& e) {
                this_thread::sleep_for(chrono::seconds(4));
                std::cout << e.what() << std::endl;
            }
        }, move(f));
    }
};

Where the control of f is further moved into the thread.

MU Tong
  • 11
  • 2
  • I think it is because when you call `mythread thrd(move(task));` the shared state from `task` is moved away, `task` no longer has any shared state, and `ftr` - which shares the same state as `task` - no longer has any shared state so there's nothing to wait on. Call `ftr.valid()` after the move and see what you get. – 1201ProgramAlarm Dec 06 '15 at 06:56

0 Answers0