How to abort async() if timeout has elapsed - c++

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.)

Related

Using a signal listener thread - how do I stop it?

A snippet from my main method:
std::atomic_bool runflag;
// ...
std::thread signaller([&]() mutable {
while (runflag) {
int sig;
int rcode = sigwait(&set, &sig);
if (rcode == 0) {
switch (sig) {
case SIGINT: {
// handle ^C
}
}
}
}
});
while (runflag) {
next = cin.get();
// handle character input
}
signaller.join();
I'm using the sigwait()-based approach for detecting SIGINT sent from the command line.
The signaller thread uses sigwait() to listen for signals. The program terminates when runflag is set false. However, the signaller thread will still be blocked at sigwait when this happens. I don't think I can use condition variables, as sigwait has no way to hook into one. Is there an alternative solution that is preferably not Linux-only?
EDIT 1: Alternatively, is there an interruptible version of sigwait?
You can use the sigtimedwait() function, which returns after a timeout given as a parameter.
You will need to check the return value from sigtimedwait() to check if it finished because of timeout or the signal arrived and then depending on this value you will need to handle signal or just check runflag and run again sigtimedwait().
Here is more about it from another answer: https://stackoverflow.com/a/58834251/11424134
You can wake up the signal-handling thread by having the process send another signal to itself, eg.
kill(getpid(), SIGUSR1);

How can I abort the call to sigwaitinfo?

Background
My objective is to handle certain signals on a dedicated thread rather than to have them handled on any of the threads that happen to be running in my process when the signal is raised.
I am doing this as follows (in this example, for signal 16 only):
On the main thread, before any other threads are started (error handling ommited)
sigset_t sigset;
sigaddset(&sigset, 16);
sigprocmask(SIG_BLOCK, &sigset, nullptr);
Then I create a thread that waits for those signals (only 16 in this example):
std::thread _thread = std::thread([&]()
{
int ret = sigwaitinfo(&sigset, nullptr);
if (ret == 16)
{
// handle signal 16
}
});
This works well.
Problem
However, I would like to be able to cancel the call to sigwaitinfo when needed.
Two Inadequate Solutions
I have tried two solutions, but neither are adequate:
1. Polling
One option (that works) is not to use sigwaitinfo but rather to use sigtimedwait which accepts a timeout argument.
This allows me to use polling and to cancel when the call next returns and some cancel flag is set.
The code in the thread then looks like this:
std::atomic<bool> _cancel (false);
std::thread _thread = std::thread([&]()
{
timespec _timespec {0, 1}; // 1 second
int ret = sigtimedwait(&sigset, nullptr, _timespec);
if (_cancel)
{
return;
}
if (ret == 16)
{
// handle signal 16
}
});
In order to cancel, I only need to set the _cancel flag in the main thread.
The problem with this solution, is that polling incurs the typical trade-off between responsiveness (of the cancellation) and the amount of busy work done checking the cancellation flag.
2. raise()/sigqueue()/kill()
In this solution I add to the signal mask a dedicated signal, for instance SIGUSR1 with the following call:
sigset_t sigset;
sigaddset(&sigset, 16);
sigaddset(&sigset, SIGUSR1); // <-- added call here
sigprocmask(SIG_BLOCK, &sigset, nullptr);
Then when I need to cancel the call to sigwaitinfo I set a cancel flag and call raise(SIGUSR1)
The code in the thread then looks like this:
std::atomic<bool> _cancel (false);
std::thread _thread = std::thread([&]()
{
int ret = sigwaitinfo(&sigset, nullptr);
if (_cancel) // <-- now check _cancel flag before handling signal
{
return;
}
if (ret == 16)
{
// handle signal 16
}
});
The cancellation is now done as follows:
_cancel = true; // <-- set the flag before raising the signal
raise(SIGUSR1);
The problem with this solution is that it doesn't work, because the call to raise() does not cause sigwaitinfo to return in the dedicated thread. I believe that according to the documentation it will only raise the signal in the executing thread itself.
sigqueue() and kill() also do not work.
Summary
Is there a way to cause sigwaitinfo to return prematurely, without requiring a loop in which calls to sigtimedwait are called with a timeout?
Use pthread_kill to send a signal to a specific thread.
E.g., instead of raise(SIGUSR1); do:
if(int rc = ::pthread_kill(_thread.native_handle(), SIGUSR1))
// Handle pthread_kill error.
This is the solution I found.
Instead of waiting with sigtimedwait, use signalfd to get a file descriptor that represents the signals to be handled. (sigprocmask or similar need to be called first as with the solution presented in the question).
Call eventfd to return an "event" file descriptor.
Call poll wait on both file descriptors. This blocks. Do so in a loop.
Signal cancellation by writing to the event file descriptor on a different thread.
When poll returns check which file descriptor was signaled by checking the revents fields.
If the event file descriptor was signaled break from the loop.
Else (the signalfd descriptor was signaled) read the signal description and handle the signal by calling the handler. Then loop around calling poll again.
I have verified that this solution is reliable.
More detailed information can be found in the documentation for:
signalfd,eventfd and poll

Choice between thread: time expired and user input

I'm writing a simple function that, when called, allows to execute 2 different actions (exclusive).
So there are two threads. User_choice waits until the user inserts an input and the Time_choice waits until time expires.
The choice_done shared var says that, if true, one thread has already started and blocking (it doesn't do anything!) the other one; Whereas thread_done says, if true, that thread (it doesn't matter which) has already finished, so func() waits until one thread finishes.
Here is the code.
The func procedure will be called more times during the program execution.
The various user_choice thread will be waiting forever on getline! Is it a problem? What if, after four times the program will call func() and the user doesn't insert anything, the 5th time the user inserts "yes"?
Will every user_choice thread continue the execution?? How can I kill the waiting thread? Are there other solutions?
How can I wait inside func() that a thread sets thread_done to true?
bool choice_done = false;
bool thread_done = false;
void func(){
boost::thread t1(boost::bind( time_choice() ));
boost::thread t2(boost::bind( user_choice() ));
//whait untile thread_done == true
do something...
}
// Time choice thread
void time_choice(){
sleep(5);
if(choice_done == false){
printf("Automatic choice\n");
choice_done == true;
do something...
thread_done = true;
}
}
// User choice thread
void user_choice(){
printf("Start emergency procedure?\n");
string tmp;
getline(cin, tmp);
if((tmp.compare("yes") == 0) && (choice_done == false)){
printf("Manual choice\n");
choice_done == true;
do something...
thread_done = true;
}
}
Having to create a thread for a timer is generally a sign of sub-optimal design. It does not scale well (imagine thousands of timers) and the code gets multi-threaded and more complex for no good reason. Also, sleep is not thread-safe on Linux.
Just use one thread with select and a timeout. select will wait on STDIN_FILENO for user input and timeout simultaneously.
Or, better, use a 3rd-party event-demultiplexing library, like libevent or boost::asio.

Including a ping timeout feature

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, ...));
}
}

When is it more appropriate to use a pthread barrier instead of a condition wait and broadcast?

I am coding a telemetry system in C++ and have been having some difficulty syncing certain threads with the standard pthread_cond_timedwait and pthread_cond_broadcast.
The problem was that I needed some way for the function that was doing the broadcasting to know if another thread acted on the broadcast.
After some hearty searching I decided I might try using a barrier for the two threads instead. However, I still wanted the timeout functionality of the pthread_cond_timedwait.
Here is basically what I came up with: (However it feels excessive)
Listen Function: Checks for a period of milliseconds to see if an event is currently being triggered.
bool listen(uint8_t eventID, int timeout)
{
int waitCount = 0;
while(waitCount <= timeout)
{
globalEventID = eventID;
if(getUpdateFlag(eventID) == true)
{
pthread_barrier_wait(&barEvent);
return true;
}
threadSleep(); //blocks for 1 millisecond
++waitCount;
}
return false;
}
Trigger Function: Triggers an event for a period of milliseconds by setting an update flag for the triggering period
bool trigger(uint8_t eventID, int timeout)
int waitCount = 0;
while(waitCount <= timeout)
{
setUpdateFlag(eventID, true); //Sets the update flag to true
if(globalEventID == eventID)
{
pthread_barrier_wait(&barEvent);
return true;
}
threadSleep(); //blocks for 1 millisecond
++waitCount;
}
setUpdateFlag(eventID, false);
return false;
}
My questions: Is another way to share information with the broadcaster, or are barriers really the only efficient way? Also, is there another way of getting timeout functionality with barriers?
Based on your described problem:
Specifically, I am trying to let thread1 know that the message it is
waiting for has been parsed and stored in a global list by thread2,
and that thread2 can continue parsing and storing because thread1 will
now copy that message from the list ensuring that thread2 can
overwrite that message with a new version and not disrupt the
operations of thread1.
It sounds like your problem can be solved by having both threads alternately wait on the condition variable. Eg. in thread 1:
pthread_mutex_lock(&mutex);
while (!message_present)
pthread_cond_wait(&cond, &mutex);
copy_message();
message_present = 0;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);
process_message();
and in thread 2:
parse_message();
pthread_mutex_lock(&mutex);
while (message_present)
pthread_cond_wait(&cond, &mutex);
store_message();
message_present = 1;
pthread_cond_broadcast(&cond);
pthread_mutex_unlock(&mutex);