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;
}
Related
When I run the following code,
#include <thread>
#include <iostream>
#include <future>
int main() {
auto fut = std::async(
std::launch::async,
[]{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "sub : " << std::this_thread::get_id() << std::endl;
}
);
std::cout << "do some on main thread" << std::endl;
fut.get();
std::cout << "main: " << std::this_thread::get_id() << std::endl;
}
I got the following output.
do some on main thread
sub : 139899103246080
main: 139899103250240
Running demo: https://godbolt.org/z/c9WedY4oq
It is the same behavior as I expected.
"do some on main thread" outputs first, because the sub thread created by std::async() waits 1 second the beggining of the thread.
So far, so good.
However, when I removed the variable fut, then I got weird behavior for me.
NOTE: This code is for only experimental purpose
#include <thread>
#include <iostream>
#include <future>
int main() {
std::async(
std::launch::async,
[]{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "sub : " << std::this_thread::get_id() << std::endl;
}
);
std::cout << "do some on main thread" << std::endl;
std::cout << "main: " << std::this_thread::get_id() << std::endl;
}
Here is the output:
sub : 139716056966912
do some on main thread
main: 139716056971072
Running demo: https://godbolt.org/z/obzzceGGr
It seems that the main thread waits until finishing the sub thread before outputing "do some on main thread".
I want to know why this behavior happens.
I got the warning message ":6:5: warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]".
Since C++20, the nodiscard attribute has been added.
See https://en.cppreference.com/w/cpp/thread/async
I guess that I got an undefined behavior due to ignoring the return value of std::async(), but I couldn't find such document, so far.
In the second case, a std::future object will still be created and returned.
That object is ephemeral and will be destructed immediately, and that leads to your problem because the std::future destructor will wait for the future to be ready before destruction continues.
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);
I have a main program, this main program executes a thread that perform an action until the user triggers a stop. The problem that I have is if I add th.join() the main program won't continue until the thread finishes. And If there is no .join() the program crashs.
#include <iostream>
#include <thread>
#include <optional>
static bool s_finished = false;
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
void startRecording(std::optional<int> t)
{
std::thread th1 (SendData, 1);
//th1.join();
std::cout << "[startRecording] Other Task" << std::endl;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
startRecording();
std::this_thread::sleep_for(5s);
stopRecording();
return 0;
}
How can I do this?
Joining a thread will cause the program to stop until that thread is finished, and that's why the program blocks. We have to call join() eventually so that all child threads finish before the program exits, but we shouldn't call join until we need the child thread to be finished.
The simplest way to get the program to work is to return the thread from startRecording, so that we have control of it inside main. Then, we join the thread at the end of main, after we call stopRecording.
#include <iostream>
#include <thread>
#include <optional>
#include <atomic>
// (1) This needs to be atomic to avoid data races
std::atomic<bool> s_finished { false };
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
std::thread startRecording(std::optional<int> t)
{
std::thread th1 (SendData, 1);
std::cout << "[startRecording] Other Task" << std::endl;
// (2) We return the thread so we can join it in main:
return th1;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
// (3) We save the thread to a variable named 'worker'
// so we can join it later. I also added an input to startRecording b/c it needed one
std::thread worker = startRecording(std::optional<int>{1});
std::this_thread::sleep_for(5s);
stopRecording();
// (4) Join here, at the end
worker.join();
return 0;
}
Now, the program prints the expected output, then exits without problems:
Start Program!
[startRecording] Other Task
Working thread: 1
Started thread id: 139985258444544
Working
Working
Working
Working
Working
[stopRecording] Other Task
I marked my changes with (1), (2), (3), and (4) in the comments of the code. They're pretty small, and if you have questions about any of them I can provide additional explanation!
Addendum - using global variables when the signature of startRecording can't be changed
In general, it's best to avoid global variables, but I know it's not always possible to do so. if startRecording's signature can't be changed, we can't return a thread, so the thread has to be accessed globally. Here's how to do that:
#include <iostream>
#include <thread>
#include <optional>
#include <atomic>
// (1) This needs to be atomic to avoid data races
std::atomic<bool> s_finished { false };
// (2) we initialize this in startRecording
std::thread worker;
using namespace std::literals::chrono_literals;
void SendData(int id)
{
std::cout << "Working thread: " << id << std::endl;
std::cout << "Started thread id: " << std::this_thread::get_id() << std::endl;
while (!s_finished)
{
std::cout << "Working\n";
std::this_thread::sleep_for(1s);
}
}
void startRecording(std::optional<int> t)
{
// (3) worker gets initialized, and thread starts
worker = std::thread(SendData, 1);
std::cout << "[startRecording] Other Task" << std::endl;
}
void stopRecording()
{
s_finished = true;
std::cout << "[stopRecording] Other Task" << std::endl;
}
int main()
{
std::cout << "Start Program!" << std::endl;
startRecording(std::optional<int>{1});
std::this_thread::sleep_for(5s);
stopRecording();
// (4) Join here, at the end
worker.join();
return 0;
}
I wrote this code to test some behaviour of boost asio together with detached threads.
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
#include <string>
#include <thread>
class printer {
public:
printer(boost::asio::io_service &io)
: timer_(io, boost::posix_time::seconds(1)), count_(0) {
timer_.async_wait(boost::bind(&printer::print, this));
}
~printer() { std::cout << "Final count is " << count_ << "\n"; }
void print() {
if (count_ < 10) {
std::cout << "thread " << std::this_thread::get_id()
<< ", count = " << count_ << std::endl;
++count_;
timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
timer_.async_wait(boost::bind(&printer::print, this));
}
}
private:
boost::asio::deadline_timer timer_;
int count_;
};
boost::asio::io_service io;
int main() {
boost::asio::io_service::work work(io);
std::cout << "main thread " << std::this_thread::get_id() << std::endl;
std::thread t([] { io.run(); });
std::thread t2([] { io.run(); });
t.detach();
t2.detach();
printer p(io);
std::string name;
std::cout << "Press a key";
std::getline(std::cin, name);
std::cout << "finished" << std::endl;
return 0;
}
I wanted to see what happens when I have two worker threads, running io_service.run method, and what happens when they are detached (especially what happens when program exits).
The first problem is that when I run this program on linux I can see only one thread id when in Printer. Somehow the second thread does not take the task from io_service, even though it should, as it is running io_service.run method.
The second problem I see is that sometimes when I press ENTER before all 10 printouts from Printer are made, the program exits normally, and sometimes not (console hangs). Why is that?
What am I doing wrong here?
The main problem in your code is that the printer get called even after its destruction: the threads are detached, so they might be running even when the main function is ended and the printer is destroyed. With this issue it is not possible to have a defined behaviour, since the threads still might work with the printer that is destroyed. The hanging sometimes happens sometimes not - undefined behavior. Why this happens hard to say specifically. What is obvious here is that the threads are working with garbage data.
Summing up the flaws:
There is a possibility for the printer instance to be used even after destruction;
There is a possibility for the io_service instance to be used even after destruction: the threads' labmdas are holding references and the run method might still be in the process of execution while the objects are destroyed (there is no any guaranties on the relative order of static variable destruction and the detached thread terminations, as well as boost::asio::io_service does not block the destructor for the run method to be finished).
My suggestion is to introduced a defined order of destruction. Unfortunately, you cannot just say: ok, I am done, threads are detached, I quit. Because there is still work going on in the threads, but the relevant objects are destroyed.
class printer {
public:
printer(boost::asio::io_service& io)
: timer_(io, boost::posix_time::seconds(1)), count_(0) {
timer_.async_wait(
boost::bind(&printer::print, this));
}
~printer() { std::cout << "Final count is " << count_ << "\n"; }
void print() {
if (count_ < 10) {
std::cout << "thread " << std::this_thread::get_id() << ", count = " << count_
<< std::endl;
++count_;
timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
timer_.async_wait(
boost::bind(&printer::print, this));
}
}
boost::asio::deadline_timer timer_;
int count_;
};
boost::asio::io_service io;
int main() {
auto work = std::unique_ptr<boost::asio::io_service::work>(
new boost::asio::io_service::work(io));
std::cout << "main thread " << std::this_thread::get_id() << std::endl;
std::thread t([&] { io.run(); });
std::thread t2([&] { io.run(); });
printer p(io);
std::string name;
std::cout << "Press a key";
std::getline(std::cin, name);
work.reset();
io.stop();
t.join();
t2.join();
std::cout << "finished" << std::endl;
return 0;
}
The result of the program depends on the order in which the two detached threads are executed. It's possible that sometimes they both start running after the main program has finished, and therefore the io object has already been destroyed.
You should try to force them to run before the main program exits, either by making them joinable or, if you really want to try them as detached, by adding a sleep before the program exits.
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;
}