C++: Simple return value from std::thread?

梦想与她 提交于 2019-11-27 03:21:15

See this video tutorial on C++11 futures.

Explicitly with threads and futures:

#include <thread>
#include <future>

void func(std::promise<int> && p) {
    p.set_value(1);
}

std::promise<int> p;
auto f = p.get_future();
std::thread t(&func, std::move(p));
t.join();
int i = f.get();

Or with std::async (higher-level wrapper for threads and futures):

#include <thread>
#include <future>
int func() { return 1; }
std::future<int> ret = std::async(&func);
int i = ret.get();

I can't comment whether it works on all platforms (it seems to work on Linux, but doesn't build for me on Mac OSX with GCC 4.6.1).

I'd say:

#include <thread>
#include <future>

int simplefunc(std::string a)
{ 
    return a.size();
}

int main()
{
      auto future = std::async(simplefunc, "hello world");
      int simple = future.get();

      return simple;
}

Note that async even propagates any exceptions thrown from the thread function

Using C++11 threads, one can't get the return value as thread exit which used to be the case with pthread_exit(...)

You need to use C++11 Future<> to get the return value. Future is created using templated argument where the template takes the return value (built in of User Defined types)..

You can fetch the value in another thread using future<..>::get(..) function.

one benefit of using future<..> is that you can check the validity of return value i.e if it's already taken, you avoid calling get() accidentally by checking the validity using future<..>::isValid(...) function.

Here is how you'll write the code.

#include <iostream>
#include <future>
using namespace std;
auto retFn() {
    return 100;
}
int main() {
    future<int> fp = async(launch::async, retFn);
    if(fp.valid())
       cout<<"Return value from async thread is => "<<fp.get()<<endl;
    return 0;
}

it should also be noted that we can get the future run on the same thread by using launch::deferred option as

 future<int> fp = async(launch::deferred, retFn);

Pass a reference / pointer to the thread with std::ref

async is just better than this, but just for science, it can be done:

void myfunc_reference(int& i);
std::thread(myfunc_reference, std::ref(output));

I suspect that the implementation of async must be doing something along those lines under the hood for us, which is essentially what you have to do in the pthread backend: How to return a value from pthread threads in C?

You have to ensure of course that the variable lifetime lasts until the thread returns.

The following runnable code example compares async and this worse method:

main.cpp

#include <cassert>
#include <future>
#include <iostream>
#include <thread>
#include <vector>

int myfunc(int i) {
    return i + 1;
}

void myfunc_reference(int& i) {
    i = myfunc(i);
}

int main() {
    unsigned int nthreads = 4;
    std::vector<int> inputs{1, 2, 3, 4};
    std::vector<int> outputs_expect{2, 3, 4, 5};

    // future and sync. Nirvana. When you are not fighting to death with types:
    // https://stackoverflow.com/questions/10620300/can-stdasync-be-use-with-template-functions
    {
        std::vector<std::future<int>> futures(nthreads);
        std::vector<int> outputs(nthreads);
        for (decltype(futures)::size_type i = 0; i < nthreads; ++i) {
            futures[i] = std::async(
                myfunc,
                inputs[i]
            );
        }
        for (decltype(futures)::size_type i = 0; i < nthreads; ++i) {
            outputs[i] = futures[i].get();
        }
        assert(outputs_expect == outputs);
    }

    // Reference arguments.
    //
    // Annoying because requires:
    //
    // - wrapping the return function to accept references
    // - keeping an array of outputs
    // - std::ref
    {
        std::vector<std::thread> threads(nthreads);
        std::vector<int> inouts(inputs);
        for (decltype(threads)::size_type i = 0; i < nthreads; ++i) {
            threads[i] = std::thread(myfunc_reference, std::ref(inouts[i]));
        }
        for (auto& thread : threads) {
            thread.join();
        }
        assert(outputs_expect == inouts);
    }
}

GitHub upstream.

Compile and run with:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp -pthread
./main.out

Tested in Ubuntu 19.04.

Here is a more specific example.

A function simulates download with a callback parameter to show progress and to cancel the download.

namespace __HeavyWork
{
    int SimulateDownload(std::function<int(int)> dlCallBack)
    {
        for (size_t i = 0; i < 100; i++)
        {
            std::this_thread::sleep_for(std::chrono::seconds(1));

            if (dlCallBack(i) == -1)
            {
                return i;
            }
        }

        return 100;
    }
}

We want to get the download status,

#include <thread>
#include <future>

    void test()
    {
        auto simulateCancellation = []()->bool {
            static bool b = true;
            if (b)
            {
                srand((unsigned int)time(NULL));
                b = false;
            }
            return (rand() % 7) == 0;
        };

        auto funDLCallback = [&](int i)->int {
            if (simulateCancellation())
            {
                return -1;
            }
            cout << "download: " << i << endl;
            return i;
        };
        auto funDownload = [&](std::promise<int> && p) {
            p.set_value(__HeavyWork::SimulateDownload(funDLCallback));
        };



        std::promise<int> p;
        auto f = p.get_future();
        std::thread t(funDownload, std::move(p));
        //dlg.doModal();
        t.join();
        cout << "return value: " << f.get() << endl;
    }

I think a reference variable reads much more intuitively.

int x = 0;
std::thread theThread(threadFunction, std::ref(x));
theThread.join();
std::cout << x << std::endl;

It all depends on your definition of "simple".

Using futures will certainly do the magic trick in a few lines of C++, but I find it debatable to hijack a mechanism that was designed for parallel processing for such a trivial use.

futures mostly make sense on multicore CPUS, where they allow a process to launch unsynchronized tasks that will leech computing power from the other cores (leaving aside the fact that finding a set of uncorelated data big enough to be worth the effort is not such a trivial matter either).

Using the whole mechanism as a workaround to retrieve a mere int return value is what I call syntax-driven software design. It sits pretty as a showcase for C++11 versatility, but it does hide considerable resource consumption under an icing of syntactic sugar.

If not for using other cores as raw power source, what is the point in creating a thread if you don't mean to communicate with it until it's done?
Because if you do, retrieving whatever status from it, be it at termination or anytime else, will be a trivial matter and you will not even think of using futures in the first place.

Except for the (arguable) convenience of it or the aesthetic appeal, what do these kinds of tricks achieve functionally that could be considered useful enough to offset the hidden costs?

Reading such answers with no proper multitasking background, the new kids on the block might be tempted by using these kind of inefficient mechanisms on a regular basis.
That would only pollute future software with more cases of Schlemiel the Painter's syndrom.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!