I'm using a deadline_timer as an asynchronous event and I'm running into a situation where, after some time, the thread waiting on the event never seems to be woken up (despite more calls to cancel()). I've been able to reproduce this using some sample code that I've pasted below; it's not exactly consistent but I have seen what I think is the same issue I'm experiencing.
boost::asio::io_service io_service;
boost::asio::deadline_timer timer(io_service);
timer.expires_at(boost::posix_time::pos_infin);
int num_events = 0;
auto waiter = [&timer, &num_events](boost::asio::yield_context context) {
while (true) {
std::cout << "waiting on event" << std::endl;
boost::system::error_code e;
timer.async_wait(context[e]);
std::cout << "got event (" << e << ")" << std::endl;
++num_events;
}
};
boost::asio::spawn(io_service, std::move(waiter));
boost::thread thread(boost::bind(&boost::asio::io_service::run, &io_service));
for (auto i = 0; i < 500000; ++i) {
timer.cancel();
std::cout << i << std::endl;
}
Am I doing something here that's unsupported and inadvertently hitting some race condition? The error code from the wait() never looks troublesome (even on the very last time it's woken up before it never seems to again). EDIT: I've also noticed the original bug on 3 different platforms (Windows, Mac and Linux) but the above test I've been using to reproduce has been on Windows.
The deadline_timer object is not threadsafe.
You're canceling it from another thread than the one that's posting the async_wait. This means the calls can race.
I'm not sure how this can completely inhibit the callback, in your sample. It seems to me that the program should /just/ quit because the tight loop to 500000 finishes quickly (doing many redundant cancels that never get processed, because the coroutine would e.g. not even have posted the new async_wait).
So maybe you mean, "why don't I get 500000 events".
UPDATE
After the comment, here's a trivial transformation that shows how you are gonna be fine calling members on the timer from within an actor. Note: this critically hinges on the idea that the io_service is run from a single thread only!
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <iostream>
using boost::thread;
using boost::asio::io_service;
int main() {
boost::asio::io_service io_service;
boost::asio::deadline_timer timer(io_service);
timer.expires_at(boost::posix_time::pos_infin);
boost::atomic_bool shutdown(false);
int num_events = 0;
auto waiter = [&timer, &num_events, &shutdown](boost::asio::yield_context context) {
while (!shutdown) {
std::cout << "waiting on event" << std::endl;
boost::system::error_code e;
timer.async_wait(context[e]);
std::cout << "got event (" << e.message() << ")" << std::endl;
++num_events;
}
};
boost::asio::spawn(io_service, std::move(waiter));
boost::thread thread(boost::bind(&boost::asio::io_service::run, &io_service));
for (auto i = 0; i < 5000; ++i) {
io_service.post([&timer, i]{
std::cout << i << std::endl;
timer.cancel();
});
}
io_service.post([&]{
shutdown = true;
timer.cancel();
});
thread.join();
std::cout << "Check: " << num_events << " events counted\n";
}
Also, it looks like you just wanted to signal a background task. As given you can simplify the program like:
See it Live On Coliru
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
using boost::thread;
using boost::asio::io_service;
int main() {
io_service svc;
int num_events = 0;
auto work = boost::make_shared<io_service::work>(svc); // keep svc running
boost::thread thread(boost::bind(&io_service::run, &svc));
for (auto i = 0; i < 500000; ++i) {
svc.post([&num_events,i]{
std::cout << "got event (" << i << ")" << std::endl;
++num_events;
});
}
work.reset();
thread.join();
std::cout << "Check: " << num_events << " events counted\n";
}
This does print all 500000 events:
got event (0)
got event (1)
got event (3)
...
got event (499998)
got event (499999)
Check: 500000 events counted
Related
I'm using boost::asio::async_read() method to asynchronously get response from server which take 10 second to process request. I am able to read response successfully. but I am attaching callback to this function to process received response which take 10 seconds. I am unable to find how i can process that callback asynchronously.
void read_response(std::string data)
{
cout << data << endl;
sleep(10);
// if you think sleep works differently if i send another rest api request from here still this function blocks the processing
}
boost::asio::async_read(socket, boost::asio::buffer(buffer), [&](const boost::system::error_code&
error,
std::size_t bytes_transferred) {
io_context.post([&]() {
read_response(buffer.data());
//read_response is not processing asynchronously
});
});
I tried posting function to io_context, i tried using
std::async(std::launch::deferred, read_handler,error,bytes_transferred,buffer.data()).wait() ;
I am new to asyn programming and c++ programming.
Indeed, don't do blocking operations on the IO service. Or grow the thread pool to accomodate for the maximum number of concurrent tasks that must be supported.
In all circumstances, copy the message into your read handler, instead of passing the buffer directly (as you did) as that invites race conditions/stale references.
Let's demonstrate using httpbin.org/delay:
Live On Coliru
#include <boost/asio.hpp>
#include <iomanip>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::tcp;
using namespace std::chrono_literals;
std::string const request = "GET /delay/10 HTTP/1.1\r\nHost: httpbin.org\r\n\r\n";
void read_response(std::string data) {
std::cout << "Asynchronously received response: " << quoted(data) << std::endl;
sleep(10);
}
int main() {
asio::io_context ioc(1);
asio::thread_pool work(10); // support 10 tasks along-side async IO
tcp::socket conn(ioc);
connect(conn, tcp::resolver(ioc).resolve("httpbin.org", "80"));
write(conn, asio::buffer(request));
std::string buf;
async_read_until( //
conn, asio::dynamic_buffer(buf), "\r\n\r\n",
[&work, &buf](boost::system::error_code ec, size_t n) {
std::cout << "\n*** Completion " << ec.message() << ", " << n << std::endl;
post(work, [msg = buf.substr(0, n)] {
// NOTE: lambda owns msg, not a reference to `buf`
read_response(std::move(msg));
});
});
std::thread([&ioc] {
ioc.run();
std::cout << "\n*** IO complete" << std::endl;
}).detach();
for (int i = 0; i < 15; ++i) {
std::cout << "." << std::flush;
std::this_thread::sleep_for(1s);
}
work.join();
std::cout << "\n*** Work Done" << std::endl;
}
This shows work continuing, "asynchronously" (relative to IO) well after ioc completes:
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 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;
}
I'm working on a project using C++.
I want a TimerHandler to be called after a specified time, but at the same time I don't want to block the current thread or any code after io.run() in the following code:
#include <iostream>
#include <string>
#include <boost/format.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
class TimerTest
{
public:
static void PrintOutTimerHandler(const boost::system::error_code&, const std::string& message)
{
std::cout << "PrintOutTimerHandler called: " << ", message: " << message << std::endl;
}
void run()
{
boost::asio::io_service io;
boost::asio::deadline_timer dt(io, boost::posix_time::seconds(5));
std::cout << "Start:\t" << std::endl;
dt.async_wait(boost::bind(PrintOutTimerHandler, boost::asio::placeholders::error, std::string("here is the message")));
// Do some job here
for (int i = 0; i < 1000000; ++i)
++i, --i;
std::cout << "End:\t" << std::endl;
io.run();
std::cout << "When to reach here 1: " << std::endl;
}
};
int main()
{
TimerTest tt;
tt.run();
std::cout << "When to reach here 2: " << std::endl;
return 0;
}
/* Current output:
Start:
End:
PrintOutTimerHandler called: , message: here is the message
When to reach here 1:
When to reach here 2:
*/
/* Expected output:
Start:
End:
When to reach here 1:
When to reach here 2:
PrintOutTimerHandler called: , message: here is the message
*/
I think I made myself clear. My questions are:
If this can be solved without
introducing a new thread, like Flex
ActionScript, that's is the best, but
I guess not (I guess ActionScript is
using a hidden thread);
If we have to
introduce an extra thread to do the
job, would you mind writing down the
pseudo code for me?
Thanks.
Peter
Here is an example . Run the io_service in a separate thread
asio::io_service io_service;
asio::thread t(boost::bind(&asio::io_service::run, &io_service));
or run it in a thread group
boost::thread_group threads;
for (std::size_t i = 0; i < my_thread_count; ++i)
threads.create_thread(boost::bind(&asio::io_service::run, &io_service));
Remember that your main thread should always run because when it exists all threads spawned will also exit.
I hope this helps.
I misunderstood what OrcunC said, but actually he is correct. Here is the modified version for your reference:
#include <iostream>
#include <string>
#include <boost/format.hpp>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
class TimerTest
{
public:
static void PrintOutTimerHandler(const boost::system::error_code&, const std::string& message)
{
std::cout << "PrintOutTimerHandler called: " << ", message: " << message << std::endl;
}
TimerTest(unsigned int timeout)
: dt(io, boost::posix_time::milliseconds(timeout))
{
}
void run()
{
std::cout << "Start:\t" << std::endl;
dt.async_wait(boost::bind(PrintOutTimerHandler, boost::asio::placeholders::error, std::string("here is the message")));
boost::thread thrd(boost::bind(&boost::asio::io_service::run, &io));
// Do some job here
for (int i = 0; i < 1000000; ++i)
++i, --i;
std::cout << "End:\t" << std::endl;
std::cout << "When to reach here 1: " << std::endl;
}
boost::asio::io_service io;
boost::asio::deadline_timer dt;
};
int main()
{
TimerTest tt(5000);
tt.run();
std::cout << "When to reach here 2: " << std::endl;
// Keep the main thread active for testing purpose. Otherwise,
// once the TimerTest object is destroyed when exiting the main() function,
// the sub thread spawed in tt.run() will also exit;
Sleep(10000);
}
/* Current output and Expected output:
Start:
End:
When to reach here 1:
When to reach here 2:
PrintOutTimerHandler called: , message: here is the message
*/
I tried using the boost deadline_timer in this simple test application, but had some trouble. The goal is for the timer to trigger every 45 milliseconds using the expires_at() member function of the deadline_timer. (I need an absolute time, so I'm not considering expires_from_now(). I am also not concerned about drift at the moment). When I run the program, wait() does not wait for 45 ms! Yet, no errors are reported. Am I using the library incorrectly somehow?
Sample program:
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
using namespace std;
int main()
{
boost::asio::io_service Service;
boost::shared_ptr<boost::thread> Thread;
boost::asio::io_service::work RunForever(Service);
Thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&boost::asio::io_service::run, &Service)));
boost::shared_ptr<boost::asio::deadline_timer> Timer(new boost::asio::deadline_timer(Service));
while(1)
{
boost::posix_time::time_duration Duration;
Duration = boost::posix_time::microseconds(45000);
boost::posix_time::ptime Start = boost::posix_time::microsec_clock::local_time();
boost::posix_time::ptime Deadline = Start + Duration;
boost::system::error_code Error;
size_t Result = Timer->expires_at(Deadline, Error);
cout << Result << ' ' << Error << ' ';
Timer->wait(Error);
cout << Error << ' ';
boost::posix_time::ptime End = boost::posix_time::microsec_clock::local_time();
(cout << "Duration = " << (End - Start).total_milliseconds() << " milliseconds" << endl).flush();
}
return 0;
}
You are mixing local time with system time. The time that asio is comparing your local time to is most likely some number of hours after the time that you want your deadline set to so wait returns immediately (depending on where you live; this same code could wait for several hours as well). To avoid this point of confusion, absolute times should be derived from asio::time_traits.
#include <boost/asio.hpp>
#include <boost/asio/time_traits.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>
using namespace std;
typedef boost::asio::time_traits<boost::posix_time::ptime> time_traits_t;
int main() {
boost::asio::io_service Service;
boost::shared_ptr<boost::thread> Thread;
boost::asio::io_service::work RunForever(Service);
Thread = boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(&boost::asio::io_service::run, &Service)));
boost::shared_ptr<boost::asio::deadline_timer> Timer(new boost::asio::deadline_timer(Service));
while(1)
{
boost::posix_time::time_duration Duration;
Duration = boost::posix_time::microseconds(45000);
boost::posix_time::ptime Start = time_traits_t::now();
boost::posix_time::ptime Deadline = Start + Duration;
boost::system::error_code Error;
size_t Result = Timer->expires_at(Deadline, Error);
cout << Result << ' ' << Error << ' ';
Timer->wait(Error);
cout << Error << ' ';
boost::posix_time::ptime End = boost::posix_time::microsec_clock::local_time();
(cout << "Duration = " << (End - Start).total_milliseconds() << " milliseconds" << endl).flush();
}
return 0;
}
That should work out for you in this case.
You are mixing asynchronous methods io_service::run with synchronous methods deadline_timer::wait. This will not work. Either use deadline_timer::async_wait with io_service::run, or skip the io_service::run and just use deadline_timer::wait. You also don't need a thread to invoke io_service:run if you go the asynchronous route, one thread will do just fine. Both concepts are explained in detail in the Basic Skills section of the Asio tutorial.
void print(const boost::system::error_code& /*e*/)
{
std::cout << "Hello, world!\n";
}
int main()
{
boost::asio::io_service io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(5));
t.async_wait(print);
io.run();
return 0;
}
Note you will need to give some work for your io_service to service prior to invoking run(). In this example, async_wait is that work.
Potentially unrelated: 45ms is quite a small delta. In my experience the smallest time for any handler to make it through the Asio epoll reactor queue is around 30 ms, this can be considerably longer at higher loads. Though it all largely depends on your application.