C++17 std::async non blocking execution - c++

I have created this C++17 code that mimics something that I need.
std::cout << "start" << std::endl;
auto a = std::async([]() -> int {
std::this_thread::sleep_for(std::chrono::seconds{ 5 });
return 2;
});
std::cout << a.get() << std::endl;
std::cout << "stop" << std::endl;
The thread sleeps here but in real example I do heavy operations and I return an integer which can be 0, 1 or 7. This is my output:
start
2
stop
This is good! This code will not freeze my UI. I know that a.get() is a blocking operation but is there a way to be non blocking?
In other words: instead of
start
2
stop
can I get as output
start
stop
2
using async? I need async because I have found online that it is useful when return a value is needed. It is also easy to read! I do not want to use std::packaged_task, promises, futures etc because async is easy.
If it cannot be non blocking can I use something else?

This code will output what you need:
std::cout << "start" << std::endl;
std::thread{
[]() {
auto a = std::async([]() -> int {
std::this_thread::sleep_for(std::chrono::seconds{ 5 });
return 2;
});
std::cout << a.get() << std::endl;
}
}.detach();
std::cout << "stop" << std::endl;
If I were you I wouldn't use async at all. If you just need to display a value and you don't want to block, you should do something else. For example:
std::cout << "start" << std::endl;
std::thread{
[]() {
//do here what you need and print the result
}
}.detach();
/* ... or ...
auto t = std::thread{ ... };
t.detach();
*/
std::cout << "stop" << std::endl;
See that detach() makes the new thread "independent" and doesn't block while join() blocks. The point is that async must block because if it has to do an operation that takes a lot of time, it has to spend that time!

Related

c++20 coroutines: boost asio co_spawn blocks from another coroutine

I do not know if this is the expected behavior of boost::asio::co_spawn (I did check the docs 1.78.0...), but if i call (e.g. co_spawn(ctx, ..., detached)) from a function, this call is async, meaning that this call does not block waiting for the completion, but returns immediately. However, if i do the same call from within another coroutine, co_spawn will block until whatever that was spawned completes. Below is the a test compiled with g++ 11.2 with boost asio 1.78.
#include <iostream>
#include <thread>
#include <chrono>
#include <coroutine>
#include <boost/asio.hpp>
#include <boost/asio/experimental/as_tuple.hpp>
using namespace boost;
using namespace boost::asio;
awaitable<void> TestCoro2(io_context& ctx) {
std::cout << "test coro1 thread id = " << std::this_thread::get_id() << std::endl;
co_return;
}
awaitable<void> TestCoro1(io_context& ctx) {
std::cout << "test coro1 thread id = " << std::this_thread::get_id() << std::endl;
std::cout << "333" << std::endl;
//co_await TestCoro2(ctx);
co_spawn(ctx, TestCoro2(ctx), detached);
std::cout << "444" << std::endl;
co_return;
}
awaitable<void> TestCoro(io_context& ctx) {
std::cout << "test coro thread id = " << std::this_thread::get_id() << std::endl;
std::cout << "111" << std::endl;
co_spawn(ctx.get_executor(), TestCoro1(ctx), detached);
std::cout << "222" << std::endl;
co_return;
}
void Test1() {
io_context ctx;
auto work = require(ctx.get_executor(), execution::outstanding_work.tracked);
std::cout << "before" << std::endl;
co_spawn(ctx.get_executor(), TestCoro(ctx), detached);
std::cout << "after" << std::endl;
ctx.run();
}
int main() {
Test1();
return 0;
}
In the example above i had not yet called ctx.run() when spawking a coro... still semantics, I would expect, to be similar...
My understanding was that first it will schedule and return, and a currently running coroutine will proceed, however i guess i was wrong. I do understand that i can also just wrap this co_spawn into a post... but i'm a bit confused on the difference in behavior...
Is this the expected behavior?
thanks!
VK
The problem is that you use the same context for all of your coroutines. co_spawn internally uses dispatch() to ensure the coroutine starts in the desired context. dispatch() calls the token synchronously if the target context is the same as the current one. So the coroutine is executed synchronously in such case, at least until the first suspension point (some co_await).
You can insert this line at the beginning of your coroutine to ensure it is always scheduled instead of being called synchronously, even when called from the same context:
co_await asio::post(ctx, asio::use_awaitable);

std::thread vs pthead, what am I doing wrong?

I'm working on a project that requires to execute some processes inside a docker container. I want to handle the case when the process doesn't terminate on time (let's say within 10 s).
I'm using this DockerClientpp library for managing the containers that basically just makes HTTP reqs to the Docker socket. Everything is fine up to this point.
To stop a container that is taking too long I'm using a separate thread. The problems is that I was able to implement it using ptheads but I cannot find a way using std::thread and lambas
Here is my working implementation with pthread
void *ContainerManager::spawnKiller(void *ref) {
ContainerManager *self = (ContainerManager *)ref;
std::unique_ptr<DockerClientpp::DockerClient> dc(new DockerClientpp::DockerClient());
std::cout << "[slave]forceStop(): Waiting " << self->timeOut << " before stopping " << self->activeId << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(self->timeOut));
try {
dc->stopContainer(self->activeId);
std::cout << "[slave]forceStop(): Container will be force-stopped" << std::endl;
} catch(std::exception &e) {
// container has already been destroyed
std::cout << "[slave]forceStop(): Error => " << e.what() << std::endl;
}
pthread_exit(0);
}
void ContainerManager::execute() {
pthread_t killerId;
pthread_create(&killerId, nullptr, &(ContainerManager::spawnKiller), (void *)this);
pthread_detach(killerId);
}
And here is my std::thread and lambda implementation that fails with SEGFAULT as soon as I try to detach the thread.
void ContainerManager::execute() {
std::thread([this]() {
std::this_thread::sleep_for(std::chrono::seconds(timeOut));
try {
dc->stopContainer(activeId);
std::cout << "[slave]forceStop(): Container will be force-stopped" << std::endl;
} catch(std::exception &e) {
// container has already been destroyed
std::cout << "[slave]forceStop(): Error => " << e.what() << std::endl;
}
}).detach();
}
And this is what gdb shows
Thread 1 "test" received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0 0x0000000000000000 in ?? ()
#1 0x00000000007c6801 in std::thread::detach() ()
#2 0x0000000000410785 in ContainerManager::execute (this=0x7fffffffe2a0, processName=...)
at ../container_manager.cpp:223
#3 0x0000000000412c99 in ContainerManager::executeNew (this=0x7fffffffe2a0, processName=...,
replace=false, language=#0x7fffffffe020: ContainerManager::GO) at ../container_manager.cpp:336
#4 0x00000000004094a9 in main () at test.cpp:36
I tried with a regular function instead of a lamba, I tried capturing the parameters, I also tried passing the parameters as arguments but I'm stuck.
I haven't tried allocating the thread dynamically with new thread(...) but from my understanding even if the std::thread variable goes out of scope, the thread is still alive.
Do you have any suggestion on what I'm doing wrong? I feel like I'm really missing something about std::thread and lambda.
The execute method is a method of the class ContainerManager that it's guaranteed not to go out of scope before the spawned thread has terminated, also the variables that I use (timeOut and activeId are fields of the object)
EDIT:
It really seems there is something wrong with detach()
If I run this
void ContainerManager::execute() {
int *t = new int;
*t = timeOut;
std::string *s = new std::string;
*s = activeId;
std::thread x([&t, &s]() {
std::cout << "LOL" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(*t));
std::unique_ptr<DockerClientpp::DockerClient> _dc(new DockerClientpp::DockerClient());
try {
_dc->stopContainer(*s);
std::cout << "[slave]forceStop(): Container will be force-stopped" << std::endl;
} catch(std::exception &e) {
// container has already been destroyed
std::cout << "[slave]forceStop(): Error => " << e.what() << std::endl;
}
});
std::cout << "Detaching" << std::endl;
if(x.joinable()) {
std::cout << ".. in a moment" << std::endl;
x.detach();
}
}
I get this output
Detaching
.. in a moment
Segmentation fault (core dumped)
EDIT 2
I tried running this code on my laptop and everything works fine
void ContainerManager::execute() {
// activeId and timeOut are fields of the ContainerManager object
std::thread([this]() {
std::this_thread::sleep_for(std::chrono::seconds(timeOut));
std::unique_ptr<DockerClientpp::DockerClient> dc(new DockerClientpp::DockerClient());
try {
dc->stopContainer(activeId);
std::cout << "[slave]forceStop(): Container will be force-stopped" << std::endl;
} catch(std::exception &e) {
// container has already been destroyed
std::cout << "[slave]forceStop(): Error => " << e.what() << std::endl;
}
}).detach();
}
In the thread, you are accessing references to variables int *t and std::string *s which are local to the ContainerManager::execute() method. As soon as ContainerManager::execute() finishes, accesses to the two variables cause undefined behaviour and in your case the SEGFAULT. Instead pass the two pointers per value to the lamdba (and even better: don't use new at all):
void ContainerManager::execute() {
int *t = new int;
*t = timeOut;
std::string *s = new std::string;
*s = activeId;
std::thread x([t, s]() { // <<--- Pass by value
std::cout << "LOL" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(*t));
std::unique_ptr<DockerClientpp::DockerClient> _dc(new DockerClientpp::DockerClient());
try {
_dc->stopContainer(*s);
std::cout << "[slave]forceStop(): Container will be force-stopped" << std::endl;
} catch(std::exception &e) {
// container has already been destroyed
std::cout << "[slave]forceStop(): Error => " << e.what() << std::endl;
}
});
std::cout << "Detaching" << std::endl;
if(x.joinable()) {
std::cout << ".. in a moment" << std::endl;
x.detach();
}
}
The segfault suggests, to me, that the class is going out of scope, even though you expect it not to. Another possibility is that you're getting a race condition on the variables you are accessing.
Rather than capturing this in the lambda, try passing all variables by copy to the lambda. This will remove any race conditions having to do with scope, and solve any potential lifetime issues as the lambda will be completely decoupled from any other threads. Of course, this means no pointers or references to data elsewhere, make sure you are really doing a full copy of timeOut and activeId.
Alternatively, rather than detach, I would recommend storing the thread as a data member of the class. Then, join in the destructor. If the thread finishes earlier, the join will basically be a no-op. If the thread is not finished, that will prevent the resources the thread is using from going out of scope until the thread is finished. This would address variables going out of scope, but not any race conditions. Race conditions can be solved by using std::atomic or mutexes.
Since the second solution (using join, std::atomic, and/or mutexes) is more convoluted and requires checking lifetimes and race conditions, I would recommend the first solution (using a lambda that doesn't capture anything, with all arguments passed by copy) if possible.

Is there a way to explicitly destroy all handlers pending on a given boost::asio::io_context?

According to my knowledge and as far as I checked the boost::asio documentation and source code there is no way to destroy explicitly all pending handlers on a given io_context aside from destroying the context itself?
I need to be able, if possible, to stop the io_context, destroy the pending handlers on the io_context, then do some other things and finally destroy all io objects (timers, pipes, etc) associated with the given io_context and the io_context itself.
I know that I can use work_guard::reset and let all pending handlers to run and then the io_context will stop by itself, but the problem is that many of the handlers may produce (post/defer/etc) new pending handlers, etc i.e. each such handler will need to be guarded with something like 'if stopped'.
I think that the io_context::shutdown does exactly this but there is no way, aside from inheritance maybe, to call explicitly the shutdown function because it's not public.
Thanks.
Trying your suggestion using the protected shutdown results in a segfault on my system. I think it's protected for a reason :)
Anyhow, it looks like a judicious combination of restart/stop/reset might do the job. It's weird that some of the handler queue apparently stays around UNLESS one does a (empty) run/run_one. In fact even a poll_one seems to suffice. So, by all means, include that.
Here's my test bed code, you might find it useful:
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
using namespace std::chrono_literals;
struct Handler {
void operator()(boost::system::error_code ec) { std::cout << "Handler invoked: " << ec.message() << std::endl; }
struct Instance { // logging only unique instance to avoid noise of moved handlers
Instance() { std::cout << "Created handler instance" << std::endl; }
~Instance() { std::cout << "Destroyed handler instance" << std::endl; }
};
std::unique_ptr<Instance> _instance = std::make_unique<Instance>();
};
int main()
{
struct Hack : boost::asio::io_context {
using boost::asio::io_context::shutdown;
} io;
auto work = make_work_guard(io);
std::cout << " -- run" << std::endl;
auto t = std::thread([&]{ io.run(); });
{
boost::asio::high_resolution_timer tim(io, 2s);
tim.async_wait(Handler{});
work.reset(); // no longer needed
std::this_thread::sleep_for(500ms);
#if 1
io.stop();
#else
io.shutdown(); // segfaults
#endif
}
std::cout << " -- timer destructed" << std::endl;
std::cout << " -- joining" << std::endl;
t.join();
std::cout << " -- empy run to flush handler queue" << std::endl;
io.reset();
//io.run();
//io.run_one();
io.poll_one();
std::cout << " -- bye" << std::endl;
}
Prints
-- run
Created handler instance
-- timer destructed
-- joining
-- empy run to flush handler queue
Handler invoked: Operation canceled
Destroyed handler instance
-- bye
UPDATE
Here's my best suggestion (apart from, I guess, not sharing io at all):
Live On Coliru
#include <boost/asio.hpp>
#include <iostream>
using namespace std::chrono_literals;
struct Handler {
void operator()(boost::system::error_code ec) { std::cout << "Handler invoked: " << ec.message() << std::endl; }
struct Instance { // logging only unique instance to avoid noise of moved handlers
Instance() { std::cout << "Created handler instance" << std::endl; }
~Instance() { std::cout << "Destroyed handler instance" << std::endl; }
};
std::unique_ptr<Instance> _instance = std::make_unique<Instance>();
};
int main()
{
std::unique_ptr<boost::asio::io_context> io;
int i = 1;
for (auto delay : { 1500ms, 500ms }) {
std::cout << " ------------------- reinitialized -------------- \n";
io = std::make_unique<boost::asio::io_context>();
boost::asio::high_resolution_timer tim(*io, 1s);
std::cout << i << " -- run" << std::endl;
auto t = std::thread([&]{ io->run(); });
tim.async_wait(Handler{});
std::this_thread::sleep_for(delay);
std::cout << i << " -- stop" << std::endl;
io->stop();
std::cout << i << " -- joining" << std::endl;
t.join();
std::cout << " ------------------- destruct ------------------- \n";
io.reset();
}
std::cout << "Bye" << std::endl;
}
Prints
------------------- reinitialized --------------
1 -- run
Created handler instance
Handler invoked: Success
Destroyed handler instance
1 -- stop
1 -- joining
------------------- destruct -------------------
------------------- reinitialized --------------
1 -- run
Created handler instance
1 -- stop
1 -- joining
------------------- destruct -------------------
Destroyed handler instance
Bye

Timer hangs main thread

I'm trying to implement timer with standard environment
Here is a code I have:
bool shutdownDetected = false;
void signal_handler(const int sigid)
{
shutdownDetected = true;
}
int main(int argc, const char * argv[])
{
signal(SIGTERM, (sig_t)signal_handler);
std::async(std::launch::async, [&] () {
std::this_thread::sleep_for( std::chrono::milliseconds{5000});
std::cout << "On TIMER!" << std::endl;
} );
std::cout << "main function" << std::endl;
while (!shutdownDetected) {
}
return EXIT_SUCCESS;
}
As result I see in output after 5 seconds:
// 5 seconds left
On Timer
main function
but would like to see:
main function
// 5 seconds left
On Timer
Seems that my implementation hangs main thread as well. How to avoid this?
Your std::async command returns an std::future, which is then immediately destroyed. The problem is that destruction of a future involves 'joining' the thread you created, which means that the destructor is going to wait until the thread has ended itself and code execution in your main thread doesn't advance until that process has completed.
Simple answer is to assign the result of your std::async call to a variable, and possibly call its get() member function in your loop that tests for termination.
auto t = std::async(std::launch::async, [&] () {
std::this_thread::sleep_for( std::chrono::milliseconds{5000});
std::cout << "On TIMER!" << std::endl;
} );
std::cout << "main function" << std::endl;
t.get();
std::async(std::launch::async, [&] () {
std::this_thread::sleep_for( std::chrono::milliseconds{5000});
std::cout << "On TIMER!" << std::endl;
} );
Does not work unless you assign the std::future returned by std::async to a variable and keep it around. I did not know why this is, clearly because I couldn't be bothered to look it up. Vincent Savard did, and linked us to documentation on the destructor for std::future which says:
it may block if all of the following are true: the shared state was created by a call to std::async, the shared state is not yet ready, and this was the last reference to the shared state.
Since the returnded std::future is not assigned to anything, it is instantly destroyed and the destructor blocks until completion.
I'm going to leave out the signal handler as it's not relevant to the problem.
#include <iostream>
#include <future>
int main()
{
auto letMeLive = std::async(std::launch::async, [] () {
std::this_thread::sleep_for( std::chrono::milliseconds{5000});
std::cout << "On TIMER!" << std::endl;
} );
std::cout << "main function" << std::endl;
letMeLive.wait(); // instead of the signal handler
return EXIT_SUCCESS;
}

std::launch::async is blocking like a sync process

I am running Visual Studio 2012 and attempting to learn how std::async works. I have created a very simple C++ console application:
#include "stdafx.h"
#include <future>
#include <iostream>
void foo() {
std::cout << "foo() thread sleep" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "foo() thread awake" << std::endl;
}
int main()
{
std::future<void> res = std::async(std::launch::async, foo);
res.get();
std::cout << "MAIN THREAD" << std::endl;
system("pause");
return 0;
}
My initial expectation was to see "MAIN THREAD" printout appearing before "foo() thread awake" since the two threads are running asynchronously, with the foo() trailing behind due to its sleeping behavior. However, that is not what is actually happening. The call to res.get() blocks until foo() wakes up, and only then does it get to the "MAIN THREAD" printout. This is indicative of a synchronous behavior, so I am wondering what if perhaps I am either missing something, or not fully grasping the implementation. I have looked through numerous posts on this matter, but still cannot make any sense of it. Any help would be appreciated!
res.get();
blocks until the async is done.
http://en.cppreference.com/w/cpp/thread/future/get
Regardless of how you tell it to run, get can't give you the results until it's done.
Well, this is how std::future::get works - it blocks until future has some result or exception to provide.
that doesn't mean that async works synchronously, it is working asynchronously, it's only because you block the thread which waits on the result.
the idea was to to launch some task asynchronously, do something meanwhile and only call get when you need the result, as you might figured out, it is not the most scale-able thing..
if you use Visual Studio 2015, you can access the await keyword both for std::future and concurrency::task (Microsoft PPL library) , and for your own compatible defined types. this achieves non-blocking behavior.
#include "stdafx.h"
#include <future>
#include <iostream>
void foo() {
std::cout << "foo() thread sleep" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "foo() thread awake" << std::endl;
}
std::future<void> entry(){
await std::async(std::launch::async, foo);
std::cout << "foo has finished, back in entry()\n";
}
int main()
{
std::cout << "MAIN THREAD" << std::endl;
entry();
std::cout << "BACK INMAIN THREAD" << std::endl;
system("pause");
return 0;
} //make sure to compile with /await flag
The problem is that res.get() has to wait for its thread to finish before getting its result (if any). To see the concurrency in motion you need to move the get() to after the other code that you want to run at the same time.
This example may make it a little clearer:
#include <ctime>
#include <cstdlib>
#include <future>
#include <iostream>
void foo(int id) {
std::cout << "foo(" << id << ") thread sleep" << std::endl;
// random sleep
std::this_thread::sleep_for(std::chrono::seconds(std::rand() % 10));
std::cout << "foo(" << id << ") thread awake" << std::endl;
}
int main()
{
std::srand(std::time(0));
std::future<void> res1 = std::async(std::launch::async, foo, 1);
std::future<void> res2 = std::async(std::launch::async, foo, 2);
std::future<void> res3 = std::async(std::launch::async, foo, 3);
std::cout << "MAIN THREAD SLEEPING" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(20));
std::cout << "MAIN THREAD AWAKE" << std::endl;
// now wait for all the threads to end
res1.get();
res2.get();
res3.get();
system("pause");
return 0;
}