I have Server A that receive's updates from Server B. I would like to add functionality to Server A where if it does not receive a message(server B will send update and ping messages) in 1 minutes time, Server A will go into a paused state and wait for messages to come in again.
I was looking into a boost::asio::deadline_timer, but I cannot figure out if it is possible, or if you can run this asynchronously. I tried a class that runs in its own thread and uses a deadline timer, but I am unable to cancel and restart the deadline timer. Here is some example code I used for that.
The implementation:
void ping_timeout::reset_timer()
{
ping_timeout_.cancel();
ping_timeout_.expires_from_now(boost::posix_time::seconds(60));
//Call to clear the cache of a static class, which is the paused state I would like
ping_timeout_.async_wait(boost::bind(&cache::empty_cache));
io_.run();
}
I am unable to cancel the deadline timer from my main thread of execution by calling reset timer, I am guessing because io_.run() is waiting for the 60 seconds to expire.
Is there any modification I can do, any any libraries out there that I can us to achieve the results I would like? Any help would be appreciated.
Thank you
Edit:
Main Loop:
ping_timeout timeout;
boost::thread(boost::bind(&cache::run_io,boost::ref(service)));
while(true)
{
std::string message = s_recv(subscriber);
}
if(message.compare("UPDATE") == 0)
{
//Process update
}
else if(message.compare("PING") == 0)
{
timeout.reset_timer();
}
}
Edit 2:
Working code:
void cache::process_cache()
{
boost::asio::io_service service;
boost::asio::io_service::work work(service);
boost::thread(boost::bind(&cache::run_io,boost::ref(service)));
boost::asio::deadline_timer timer(service,boost::posix_time::seconds(60));
timer.async_wait(boost::bind(&cache::empty_cache,boost::asio::placeholders::error));
while(true)
{
std::string message = s_recv(subscriber);
if(message.compare("UPDATE") == 0)
{
//Process update
}
else if(message.compare("PING") == 0)
{
timer.cancel();
timer.expires_from_now(boost::posix_time::seconds(60));
timer.async_wait(boost::bind(&cache::empty_cache,boost::asio::placeholders::error));
}
}
}
void cache::empty_cache(const boost::system::error_code& e)
{
if(e.value() == 0)
{
//Clear cache
}
}
void cache::run_io(boost::asio::io_service& io)
{
io.run();
}
boost::asio::io_service::run() is a blocking call. In your specific case, you should avoid calling that in your main thread.
Note: In a typical async-driven app, you should build your app around the run method.
As for the timer code logic, something like that should work :
boost::asio::io_service service;
// Creates a work object to prevent the thread from exiting after the first job is done
boost::asio::io_service::work work(service);
// Creates the timer and post the aync wait now, will only start when service.run() is called
boost::asio::deadline_timer timer(service, boost::posix_time::seconds(60));
timer.async_wait(boost::bind(&cache::empty_cache, ...));
// Starts the worker thread to allow the timer to asynchronously waits
boost::thread ping_thread(boost::bind(&boost::asio::io_service::run, &service));
while (true) // you should add a condition in order to leave if the timer expires
{
std::string message = s_recv(subscriber);
/**/ if (message == "UPDATE")
{
// Process update
}
else if (message == "PING")
{
// Cancel the current timer
timer.cancel();
// Start another async wait
timer.async_wait(boost::bind(&cache::empty_cache, ...));
}
}
Related
I got a simple server app. When new client connecting, it handles request from client and send data back to it. My problem is to provide a async execution of handle thread. Now, when began a handle thread it stops acceptor loop and wait for return of corresponding function.
The question is how to organize the continuation of acceptor loop (to be able to simultaneously handle other connection) after starting a handle thread?
Server.h:
class Server
{
private:
//Storage
boost::asio::io_service service;
boost::asio::ip::tcp::acceptor* acceptor;
boost::mutex mtx;
//Methods
void acceptorLoop();
void HandleRequest(boost::asio::ip::tcp::socket* clientSock);
public:
Server();
};
Server.cpp
void Server::acceptorLoop()
{
std::cout << "Waiting for clients..." << std::endl;
while (TRUE)
{
boost::asio::ip::tcp::socket clientSock (service);
acceptor->accept(clientSock); //new socket accepted
std::cout << "New client joined! ";
boost::thread request_thread (&Server::HandleRequest, this, &clientSock); //create a thread
request_thread.join(); //here I start thread, but I want to continue acceptor loop and not wait until function return.
}
}
void Server::HandleRequest(boost::asio::ip::tcp::socket* clientSock)
{
if (clientSock->available())
{
//Works with socket
}
}
Server::Server()
{
acceptor = new boost::asio::ip::tcp::acceptor(service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 8001));
acceptorLoop(); //loop started
}
You have two main problems here:
Thread joining - you are waiting for thread finish before accept new connection
Using pointer to a socket created on a stack
I recommend you this changes:
boost::asio::ip::tcp::socket clientSock (service);
acceptor->accept(clientSock); //new socket accepted
std::cout << "New client joined! ";
std::thread{std::bind(&Server::HandleRequest, this, std::placeholders::_1), std::move(clientSock)}.detach();
And HandleRequest will change to this:
void Server::HandleRequest(boost::asio::ip::tcp::socket&& clientSock)
{
if (clientSock.available())
{
//Works with socket
}
}
You can also store thread somewhere and join it later instead of detaching.
So why do you call join? Join is about waiting for a thread to finish, and you say you don't want to wait for the thread, so, well... just don't call join?
I am working with the boost::asio tcp, version 1.57, creating a custom server/client, roughly following this example: Async_Tcp_Client , but I'm running the io_service run() in it's own thread per server/client. Also, there can be multiple server/clients per application.
Following the example I put my await_output function to sleep when I DON'T want to send a Message, and waking it up when I do want to send one (via async_write). After a varying amount of send-operations (sometimes less then 10, sometimes several thousand) I run into strange behaviour of my await_output Deadline (a boost deadline timer).
At some point, the async_wait against the timer just "disappears" and doesn't return when I cancel the deadline to send a message.
The transmit function, that is called by the Application owning the Client/Server (only by the application though, I guess it is not very threadsafe);
The await_output function that is waiting on the mOutputQueueDeadline;
And the handle_write function:
void SocketTcp::transmit(std::string pMsg) {
if (mStopped)
{ return; }
mOutputQueue.push(pMsg); // a global queue
// Signal that the output queue contains messages. Modifying the expiry
// will wake the output actor, if it is waiting on the timer.
size_t quits = mOutputQueueDeadline.expires_at(boost::posix_time::neg_infin);
//this returns '0' when the error occurs
}
void SocketTcp::await_output(const boost::system::error_code& ec)
{
if (mStopped)
{ return; }
if (mOutputQueue.empty())
{
size_t quits = mOutputQueueDeadline.expires_at(boost::posix_time::pos_infin);
mOutputQueueDeadline.async_wait(boost::bind(&SocketTcp::await_output, this, _1));
//this async_wait starts a wait on the deadline, that sometimes never returns!
}
else
{
boost::asio::async_write(mSocket,
boost::asio::buffer(mOutputQueue.front()),
boost::bind(&SocketTcp::handle_write, this, _1));
}
}
void SocketTcp::handle_write(const boost::system::error_code& ec)
{
if (mStopped)
{ return; }
if(!ec)
{
mOutputQueue.pop(); //remove sent element from queue
boost::system::error_code errcode;
await_output(errcode); //start the waiting actor for outgoing messages
}
else
{
mConnected = false; //update the connection status
this->stop();
}
}
I tried implementing a workaround, restarting the await_output in transmit() when expire_at returns 0, but that leads to TWO actors beeing awakened the next time I send a message, and then running into a crash (String iterator not dereferencable - the design doesn't allow for parallel send OP, much less trying to send the same message...)
I tried debugging with the BOOST_ASIO_ENABLE_HANDLER_TRACKING option, and found the error here:
#asio|1468415460.456019|0|deadline_timer#000000000050AB88.cancel //transmit cancels the timer
#asio|1468415460.456019|>474|ec=system:995 //await_output is called
#asio|1468415460.456019|474*479|socket#000000000050A9D8.async_send //starts the async send
#asio|1468415460.457019|<474|
#asio|1468415460.457019|>479|ec=system:0,bytes_transferred=102 //async send returns to it's handler
#asio|1468415460.457019|479|deadline_timer#000000000050AB88.cancel
//this cancel op is the only difference to the 'normal' order,
//not sure where it originates though!!
#asio|1468415460.457019|479*480|deadline_timer#000000000050AB88.async_wait //the handler starts the new async wait
//handler 480 never gets called when the deadline is canceled the next time
#asio|1468415460.457019|<479|
I'm pretty new to c++ as well as the stackoverflow (even though it has already safed me multiple times!) so please tell me if I can improve my question somehow!
I have a function called read_packet. This function remains blocked while there is no connection request or the timer is signaled.
The code is the following:
std::size_t read_packet(const std::chrono::milliseconds& timeout,
boost::system::error_code& error)
{
// m_timer_ --> boost::asio::high_resolution_timer
if(!m_is_first_time_) {
m_is_first_time = true;
// Set an expiry time relative to now.
m_timer_.expires_from_now( timeout );
} else {
m_timer_.expires_at( m_timer_.expires_at() + timeout );
}
// Start an asynchronous wait.
m_timer_.async_wait(
[ this ](const boost::system::error_code& error){
if(!error) m_is_timeout_signaled_ = true;
}
);
auto result = m_io_service_.run_one();
if( !m_is_timeout_signaled_ ) {
m_timer_.cancel();
}
m_io_service_.reset();
return result;
}
The function works correctly while not receiving a connection request. All acceptances of requests are asynchronous.
After accepting a connection, the run_one() function does not remains blocked the time set by the timer. The function always returns 1 (one handle has been processed). This handle corresponds to the timer.
I do not understand why this situation occurs.
Why the function is not blocked the time required for the timer?
Cheers.
NOTE: This function is used in a loop.
UPDATE:
I have my own io_service::run() function. This function performs other actions and tasks. I want to listen and process the network level for a period of time:
If something comes on the network level, io_service::run_one() returns and read_packet() returns the control to my run() function.
Otherwise, the timer is fired and read_packet() returns the control to my run() function.
Everything that comes from the network level is stored in a data structure. Then my run() function operates on that data structure.
It also runs other options.
void run(duration timeout, boost::system::error_code& error)
{
time_point start = clock_type::now();
time_point deadline = start + timeout;
while( !stop() ) {
read_packet(timeout, error);
if(error) return;
if(is_timeout_expired( start, deadline, timeout )) return;
// processing network level
// other actions
}
}
In my case, the sockets are always active until a client requests the closing of the connection.
During a time slot, you manage the network level and for another slot you do other things.
After reading the question more closely I got the idea that you are actually trying to use Asio to get synchronous IO, but with a timeout on each read operation.
That's not what Asio was intended for (hence, the name "Asynchronous IO Library").
But sure, you can do it if you insist. Like I said, I feel you're overcomplicating things.
In the completion handler of your timer, just cancel the socket operation if the timer had expired. (Note that if it didn't, you'll get operation_aborted, so check the error code).
Small selfcontained example (which is what you should always do when trying to get help, by the way):
Live On Coliru
#include <boost/asio.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <iostream>
struct Program {
Program() { sock_.connect({ boost::asio::ip::address_v4{}, 6771 }); }
std::size_t read_packet(const std::chrono::milliseconds &timeout, boost::system::error_code &error) {
m_io_service_.reset();
boost::asio::high_resolution_timer timer { m_io_service_, timeout };
timer.async_wait([&](boost::system::error_code) {
sock_.cancel();
});
size_t transferred = 0;
boost::asio::async_read(sock_, boost::asio::buffer(buffer_), [&](boost::system::error_code ec, size_t tx) {
error = ec;
transferred = tx;
});
m_io_service_.run();
return transferred;
}
private:
boost::asio::io_service m_io_service_;
using tcp = boost::asio::ip::tcp;
tcp::socket sock_{ m_io_service_ };
std::array<char, 512> buffer_;
};
int main() {
Program client;
boost::system::error_code ec;
while (!ec) {
client.read_packet(std::chrono::milliseconds(100), ec);
}
std::cout << "Exited with '" << ec.message() << "'\n"; // operation canceled in case of timeout
}
If the socket operation succeeds you can see e.g.:
Exited with 'End of file'
Otherwise, if the operation didn't complete within 100 milliseconds, it will print:
Exited with 'Operation canceled'
See also await_operation in this previous answer, which generalizes this pattern a bit more:
boost::asio + std::future - Access violation after closing socket
Ok, The code is incorrect. When the timer is canceled, the timer handler is always executed. For this reason io_service::run_one() function is never blocked.
More information: basic_waitable_timer::cancel
Thanks for the help.
I am using the HTML Server 3 example from boost as my learning tool (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/examples.html#boost_asio.examples.http_server_3) for asynchronous message handling.
I have taken the example, and turned it into a library with a server object I can instantiate in my programs. The only thing I have done to the above example is remove the main.cpp and compile it as a library. And it works to the extend that I can instantiate the server object in my code, and pass messages to it from the command line.
Where I am struggling is how to terminate the server gracefully. From the sample code I see this:
server::server(const std::string& address, const std::string& port,
std::size_t thread_pool_size,
Handler &handler)
: thread_pool_size_(thread_pool_size),
signals_(io_service_),
acceptor_(io_service_),
new_connection_(),
request_handler_(handler)
{
// Register to handle the signals that indicate when the server should exit.
// It is safe to register for the same signal multiple times in a program,
// provided all registration for the specified signal is made through Asio.
signals_.add(SIGINT);
signals_.add(SIGTERM);
signals_.async_wait(boost::bind(&server::handle_stop, this));
So an asynchronous thread is set up to listen for signals and respond to them
I have implemented this server object in a thread in my program as follows:
class ServerWorker
{
public:
ServerWorker(std::string theHost, std::string thePort)
{
Host = theHost;
Port = thePort;
}
void Start()
{
try
{
MYRequestHandler handler;
int nCores = boost::thread::hardware_concurrency();
server *mServer = new server(Host, Port, nCores, handler);
svr->run();
}
catch(std::exception &e) { /* do something */ }
}
void Stop()
{
mServer->stop(); // this should raise a signal and send it to the server
// but don't know how to do it
}
private:
std::string Host;
std::string Port;
server *mServer;
};
TEST(BSGT_LBSSERVER_STRESS, BSGT_SINGLETON)
{
// Launch as server on a new thread
ServerWorker sw(BSGT_DEFAULT_IPADDRESS, BSGT_DEFAULT_PORT_STR);
boost::function<void()> th_func = boost::bind(&ServerWorker::Start, &sw);
boost::thread swThread = boost::thread(th_func);
// DO SOMETHING
// How do I signal the server in the swThread to stop?
}
How do I implement the stop() method on the server object to send the signal to itself? I have tried:
1) raise(SIGTERM) - kills the whole program
2) raise(SIGINT) - kills the whole program
raise() is appropriate for having a process signal itself.
void ServerWorker::Stop()
{
std::raise(SIGTERM);
}
Be aware that raise() is asynchronous. It will issue the signal and return immediately. Hence, control may continue before the io_service processes the enqueued SignalHandler.
void run_server()
{
// Launch as server on a new thread
ServerWorker server_worker(...);
boost::thread worker_thread([&server_worker]() { server_worker.Start(); });
...
// Raises SIGTERM. May return before io_service is stopped.
server_worker.Stop();
// Need to synchronize with worker_thread. The `worker_thread` may still be
// in `ServerWorker::Start()` which would go out of scope. Additionally,
// the `worker_thread` is joinable, so its destructor may invoke
// `std::terminate()`.
}
Here is a minimal example demonstrating using Boost.Asio signal handling, raise(), and synchronization:
#include <cassert>
#include <csignal>
#include <iostream>
#include <thread>
#include <boost/asio.hpp>
int main()
{
boost::asio::io_service io_service;
// Prevent io_service from running out of work.
boost::asio::io_service::work work(io_service);
// Boost.Asio will register an internal handler for SIGTERM.
boost::asio::signal_set signal_set(io_service, SIGTERM);
signal_set.async_wait(
[&io_service](
const boost::system::error_code& error,
int signal_number)
{
std::cout << "Got signal " << signal_number << "; "
"stopping io_service." << std::endl;
io_service.stop();
});
// Raise SIGTERM.
std::raise(SIGTERM);
// By the time raise() returns, Boost.Asio has handled SIGTERM with its
// own internal handler, queuing it internally. At this point, Boost.Asio
// is ready to dispatch this notification to a user signal handler
// (i.e. those provided to signal_set.async_wait()) within the
// io_service event loop.
std::cout << "io_service stopped? " << io_service.stopped() << std::endl;
assert(false == io_service.stopped());
// Initiate thread that will run the io_service. This will invoke
// the queued handler that is ready for completion.
std::thread work_thread([&io_service]() { io_service.run(); });
// Synchornize on the work_thread. Letting it run to completion.
work_thread.join();
// The io_service has been explicitly stopped in the async_wait
// handler.
std::cout << "io_service stopped? " << io_service.stopped() << std::endl;
assert(true == io_service.stopped());
}
Output:
io_service stopped? 0
Got signal 15; stopping io_service.
io_service stopped? 1
I have a questions about async() function or any other way to solve my problem. I send to the server specified type of message and I wait for a specific
response.
I have function receive() which waits for response from server. I call this function inside async().
Sample of code:
while (true) {
future_receive = std::async(std::launch::async, [&] {
receive();
});
do {
status = future_receive.wait_for(chrono::seconds(timeLimit));
if (status == std::future_status::timeout){
//if timeout, abort async() function
}
} while (status != std::future_status::ready);
}
What is my problem? In this case, if I get "timeout", async() function will work on,
will wait until something comes, even if it will never come, and in the next cycle will be called again,
and new thread will be created. How to avoid this?
How I can abort async() when "timeout" has elapsed. Maybe any other way without async() to solve this problem. I would like to use only the standard library of C++?
The asynchronous thread has to cooperate and check whether it should continue working or give up, there is no portable way to force it to stop without its cooperation.
One way to do that is to replace the receive() call with a similar one that has a timeout, and have the thread give up after a timeout, or check a flag after a timeout to indicate whether to continue.
while (true) {
std::atomic<bool> stop{false};
future_receive = std::async(std::launch::async, [&] {
while (!stop)
try_receive(std::chrono::seconds(1));
});
do {
status = future_receive.wait_for(chrono::seconds(timeLimit));
if (status == std::future_status::timeout){
stop = true;
}
} while (status != std::future_status::ready);
}
Now the asynchronous thread will only block for up to a second, then will check if it's been told to give up, otherwise it will try receiving again.
If you're willing to sacrifice portability, something like this should work on platforms where std::thread is implemented in terms of POSIX threads:
while (true) {
std::atomic<pthread_t> tid{ pthread_self() };
future_receive = std::async(std::launch::async, [&] {
tid = pthread_self();
receive();
});
do {
status = future_receive.wait_for(chrono::seconds(timeLimit));
if (status == std::future_status::timeout){
while (tid == pthread_self())
{ /* wait for async thread to update tid */ }
pthread_cancel(tid);
}
} while (status != std::future_status::ready);
}
This assumes that there is a Pthreads cancellation point somewhere in the receive() call, so that the pthread_cancel will interrupt it.
(This is slightly more complicated than I would like. It's necessary to store some known value in the atomic initially in order to handle the situation where the async thread has not even started running yet when the calling thread gets a timeout and tries to cancel it. To handle that I store the calling thread's ID, then wait until it's changed before calling pthread_cancel.)