nlib
misc/threading/future/future.cpp

This is a sample of Future. Using Future/Promise allows for the simple implementation of safe synchronization and exchange of results between asynchronous processes.

PackagedTask and Async are written using Future and Promise, which allows for processes to be written in a simplified way.

using nlib_ns::threading::Future;
using nlib_ns::threading::Promise;
using nlib_ns::threading::PackagedTask;
using nlib_ns::threading::Thread;
using nlib_ns::threading::ThreadSettings;
using nlib_ns::threading::ThreadArg;
static int DeferredPlus(int x, int y) {
return x + y;
}
static int Square(Future<int>& x) { // NOLINT
// Future::Get() will not block if
int tmp = x.Get();
return tmp * tmp;
}
bool UsePackagedTask() {
// Use 'PackagedTask<R(...)>' and 'GetFuture()' function to retrieve 'Future<R>'.
// the template arguments for PackagedTask are the return type and the argument types.
PackagedTask<int(int, int)> task; // NOLINT
if (nlib_is_error(task.Init(DeferredPlus))) return false;
Future<int> future;
// you can get a Future object from PackagedTask.
// The result of PackagedTask on the other thead is retrieved safely by it.
if (nlib_is_error(task.GetFuture(&future))) {
return false;
} else {
Thread th;
ThreadSettings settings;
settings.SetDetachState(true);
int val1 = 1;
int val2 = 2;
if (nlib_is_error(th.Start(settings, task, val1, val2, nlib_ns::move_tag())))
return false;
}
nlib_printf("Start PackagedTask{ sleep(2000msec); return x(1) + y(2); }\n");
// Future::Get() waits until the result is available.
// you can use Future::WaitFor(), Future::WaitUnitl() for timeout.
int result = future.Get();
nlib_printf("Result of PackagedTask = %d\n", result);
return true;
}
bool UseAsync() {
// you can also use Async instead of PackagedTask.
// A thread is invoked inside Async, and it is detached inside Async.
Future<int> future;
nlib_printf("Start Async{ sleep(2000msec); return x(2) + y(3); }\n");
if (nlib_is_error(Async(&future, DeferredPlus, 2, 3))) return false;
int result = future.Get();
nlib_printf("Result of Async = %d\n", result);
return true;
}
void CreateData(UniquePtr<ThreadArg<Promise<UniquePtr<int[]> > > >& ptr) { // NOLINT
// CreateData() runs concurrently with UsePromiseAndFuture().
// You can package I/O tasks by Promise/Future.
" Another thread allocates memory and sets data,\n"
" then returns the memory to the main thread.\n");
UniquePtr<int[]> data(new int[1024]);
for (int i = 0; i < 1024; ++i) {
data[i] = i;
}
// You can avoid memory leaks if the main thread gives up the I/O.
errno_t e = ptr->arg1.SetValue(data.release());
NLIB_UNUSED(e);
NLIB_ASSERT_NOERR(e);
}
bool UsePromiseAndFuture() {
ThreadArg<Promise<UniquePtr<int[]> > >::ArgType p(new ThreadArg<Promise<UniquePtr<int[]> > >());
Future<UniquePtr<int[]> > myfuture;
p->arg1.GetFuture(&myfuture);
p->func = CreateData;
nlib_printf("Start Promise/Future\n");
{
Thread th;
ThreadSettings settings;
settings.SetDetachState(true);
if (nlib_is_error(th.StartRaw(settings, p))) return false;
}
// you can use Future::Release() to release the ownership of the object.
int* ptr = myfuture.Get();
NLIB_ASSERT(ptr);
nlib_printf("End\n");
// verify the data
for (int i = 0; i < 1024; ++i) {
if (ptr[i] != i) return false;
}
return true;
}
bool UseContinuation() {
// Read the article below about continuation
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3558.pdf
nlib_printf("Start UseContinuation\n");
Future<int> future1;
if (nlib_is_error(Async(&future1, DeferredPlus, 2, 3))) return false;
// Square() will start after 'future1' becomes valid (after DefferedPlus returns).
// Square() takes the future of DefferedPlus as the argument.
Future<int> future2;
if (nlib_is_error(future1.Then(&future2, Square))) return false;
errno_t e = future1.Wait();
if (nlib_is_error(e)) return false;
int result = future2.Get();
nlib_printf("x = DefferedPlus(2, 3), Square(x, x) = %d, %d\n", future1.Get(), result);
return true;
}
static bool SampleMain(int, char**) {
return UsePackagedTask() && UseAsync() && UsePromiseAndFuture() && UseContinuation();
}
NLIB_MAINFUNC