Stopping boost::asio::io_service::run() from concurrent destructor - c++

Can anybody explain me why this program does not terminate (see the comments)?
#include <boost/asio/io_service.hpp>
#include <boost/asio.hpp>
#include <memory>
#include <cstdio>
#include <iostream>
#include <future>
class Service {
public:
~Service() {
std::cout << "Destroying...\n";
io_service.post([this]() {
std::cout << "clean and stop\n"; // does not get called
// do some cleanup
// ...
io_service.stop();
std::cout << "Bye!\n";
});
std::cout << "...destroyed\n"; // last printed line, blocks
}
void operator()() {
io_service.run();
std::cout << "run completed\n";
}
private:
boost::asio::io_service io_service;
boost::asio::io_service::work work{io_service};
};
struct Test {
void start() {
f = std::async(std::launch::async, [this]() { service(); std::cout << "exiting thread\n";});
}
std::future<void> f;
Service service;
};
int main(int argc, char* argv[]) {
{
Test test;
test.start();
std::string exit;
std::cin >> exit;
}
std::cout << "exiting program\n"; // never printed
}

The real issue is that destruction of io_service is (obviously) not thread-safe.
Just reset the work and join the thread. Optionally, set a flag so your IO operations know shutdown is in progress.
You Test and Service classes are trying to share responsibility for the IO service, that doesn't work. Here's much simplified, merging the classes and dropping the unused future.
Live On Coliru
The trick was to make the work object optional<>:
#include <boost/asio.hpp>
#include <boost/optional.hpp>
#include <iostream>
#include <thread>
struct Service {
~Service() {
std::cout << "clean and stop\n";
io_service.post([this]() {
work.reset(); // let io_service run out of work
});
if (worker.joinable())
worker.join();
}
void start() {
assert(!worker.joinable());
worker = std::thread([this] { io_service.run(); std::cout << "exiting thread\n";});
}
private:
boost::asio::io_service io_service;
std::thread worker;
boost::optional<boost::asio::io_service::work> work{io_service};
};
int main() {
{
Service test;
test.start();
std::cin.ignore(1024, '\n');
std::cout << "Start shutdown\n";
}
std::cout << "exiting program\n"; // never printed
}
Prints
Start shutdown
clean and stop
exiting thread
exiting program

See here: boost::asio hangs in resolver service destructor after throwing out of io_service::run()
I think the trick here is to destroy the worker (the work member) before calling io_service.stop(). I.e. in this case the work could be an unique_ptr, and call reset() explicitly before stopping the service.
EDIT: The above helped me some time ago in my case, where the ioservice::stop didn't stop and was waiting for some dispatching events which never happened.
However I reproduced the problem you have on my machine and this seems to be a race condition inside ioservice, a race between ioservice::post() and the ioservice destruction code (shutdown_service). In particular, if the shutdown_service() is triggered before the post() notification wakes up the other thread, the shutdown_service() code removes the operation from the queue (and "destroys" it instead of calling it), therefore the lambda is never called then.
For now it seems to me that you'd need to call the io_service.stop() directly in the destructor, not postponed via the post() as that apparently doest not work here because of the race.

I was able to fix the problem by rewriting your code like so:
class Service {
public:
~Service() {
std::cout << "Destroying...\n";
work.reset();
std::cout << "...destroyed\n"; // last printed line, blocks
}
void operator()() {
io_service.run();
std::cout << "run completed\n";
}
private:
boost::asio::io_service io_service;
std::unique_ptr<boost::asio::io_service::work> work = std::make_unique<boost::asio::io_service::work>(io_service);
};
However, this is largely a bandaid solution.
The problem lies in your design ethos; specifically, in choosing not to tie the lifetime of the executing thread directly to the io_service object:
struct Test {
void start() {
f = std::async(std::launch::async, [this]() { service(); std::cout << "exiting thread\n";});
}
std::future<void> f; //Constructed First, deleted last
Service service; //Constructed second, deleted first
};
In this particular scenario, the thread is going to continue to attempt to execute io_service.run() past the lifetime of the io_service object itself. If more than the basic work object were executing on the service, you very quickly begin to deal with undefined behavior with calling member functions of deleted objects.
You could reverse the order of the member objects in Test:
struct Test {
void start() {
f = std::async(std::launch::async, [this]() { service(); std::cout << "exiting thread\n";});
}
Service service;
std::future<void> f;
};
But it still represents a significant design flaw.
The way that I usually implement anything which uses io_service is to tie its lifetime to the threads that are actually going to be executing on it.
class Service {
public:
Service(size_t num_of_threads = 1) :
work(std::make_unique<boost::asio::io_service::work>(io_service))
{
for (size_t thread_index = 0; thread_index < num_of_threads; thread_index++) {
threads.emplace_back([this] {io_service.run(); });
}
}
~Service() {
work.reset();
for (std::thread & thread : threads)
thread.join();
}
private:
boost::asio::io_service io_service;
std::unique_ptr<boost::asio::io_service::work> work;
std::vector<std::thread> threads;
};
Now, if you have any infinite loops active on any of these threads, you'll still need to make sure you properly clean those up, but at least the code specific to the operation of this io_service is cleaned up correctly.

Related

std::promise external code, async cancellation

Suppose you have some external synchronous code you cannot modify, and you require it to run async but also require it to be cancellable. If the external code is blocking then I have two options.
A) Fool the user and let my async method return immediately on cancellation, well aware that the code is still running to completion somewhere.
B) Cancel execution
I would like to implement an interface for option B
namespace externallib {
std::uint64_t timeconsuming_operation()
{
std::uint64_t count = 0;
for (auto i = 0; i < 1E+10; ++i)
{
count++;
}
return count;
}
}
template <typename R>
struct async_operation
{
struct CancelledOperationException
{
std::string what() const
{
return what_;
}
private:
std::string what_{ "Operation was cancelled." };
};
template<typename Callable>
async_operation(Callable&& c)
{
t_ = std::thread([this, c]()
{
promise_.set_value(c()); // <-- Does not care about cancel(), mostly because c() hasn't finished..
});
}
std::future<R> get()
{
return promise_.get_future();
}
void cancel()
{
promise_.set_exception(std::make_exception_ptr(CancelledOperationException()));
}
~async_operation()
{
if (t_.joinable())
t_.join();
}
private:
std::thread t_;
std::promise<R> promise_;
};
void foo()
{
async_operation<std::uint64_t> op([]()
{
return externallib::timeconsuming_operation();
});
using namespace std::chrono_literals;
std::this_thread::sleep_for(5s);
op.cancel();
op.get();
}
In the code above I cannot wrap my head around the limitation of external code being blocking, how, if at all, is it possible to cancel execution early?
Short answer:
Don't cancel/terminate thread execution unless it is mission critical. Use approach "A" instead.
Long answer:
As #Caleth noted, there is no standard nor cross platform way to do this. All you can do is to get a native handle to a thread and use platform specific function. But there are some important pit falls.
win32
You may terminate a thread with TerminateThread function, but:
stack variables will not be destructed
thread_local variables will not be destructed
DLLs will not be notified
MSDN says:
TerminateThread is a dangerous function that should only be used in
the most extreme cases.
pthread
Here situation is slightly better. You have a chance to free your resources when pthread_cancel is got called, but:
By default, target thread terminates on cancellation points. It means that you cannot cancel a code that doesn't have any cancellation point. Basically, for(;;); won't be canceled at all.
Once cancellation point is reached, implementation specific exception is thrown, so resources can be gracefully freed.
Keep in mind, that this exception can be caught by try/catch, but it's required to be re-thrown.
This behavior can be disabled by pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, nullptr);. But in case cancellation point is not met, resources won't be freed (as for win32)
Example
#include <iostream>
#include <thread>
#include <chrono>
#if defined(_WIN32)
#include <Windows.h>
void kill_thread(HANDLE thread) {
TerminateThread(thread, 0);
}
#else
#include <pthread.h>
void kill_thread(pthread_t thread) {
pthread_cancel(thread);
}
#endif
class my_class {
public:
my_class() { std::cout << "my_class::my_class()" << std::endl; }
~my_class() { std::cout << "my_class::~my_class()" << std::endl; }
};
void cpu_intensive_func() {
#if !defined(_WIN32)
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, nullptr);
#endif
my_class cls;
for(;;) {}
}
void io_func() {
my_class cls;
int a;
std::cin >> a;
}
void io_func_with_try_catch() {
my_class cls;
try {
int a;
std::cin >> a;
} catch(...) {
std::cout << "exception caught!" << std::endl;
throw;
}
}
void test_cancel(void (*thread_fn) (void)) {
std::thread t(thread_fn);
std::this_thread::sleep_for(std::chrono::seconds(1));
kill_thread(t.native_handle());
t.join();
std::cout << "thread exited" << std::endl;
std::cout << "--------------------" << std::endl;
}
int main() {
test_cancel(cpu_intensive_func);
test_cancel(io_func);
test_cancel(io_func_with_try_catch);
return 0;
}
You may see that:
The destructor is never called on windows.
Removing of pthread_setcanceltype leads to hang.
The internal pthread exception could be caught.
There is no portable way to end a thread before it wants to.
Depending on your platform, there may be ways of ending a thread, which you will probably need to get std::thread::native_handle to utilise. This is highly likely to lead to undefined behaviour, so I don't recommend it.
You can run that external synchronous code in another process and terminate that entire process. This way the interruption won't affect your process and cause undefined behaviour.

What is a valid way to stop a std::thread by an external signal?

This is a code which works not as designed please explain me what is wrong here (code simplified to make this more readable).
shm_server server;
std::thread s{server};
// some work...
std::cout << "press any key to stop the server";
_getch();
server.stop();
s.join();
It looks like I call a stop method for another copy of shm_server class.
because stop() only sets std::atomic_bool done; (shm_server member) to true but I see that thread function (this is operator() of shm_server) still sees done equal to false.
std::thread has only move contructor?
How to send a signal to server correctly in this typical case?
class shm_server {
std::atomic_bool done;
public:
shm_server() : done{false} {}
shm_server(shm_server& ) : done{false} {}
void operator()() {
while (!done) {
//...
}
}
void stop() {
done = true;
}
};
You have somehow shot yourself into the foot by making shm_server copyable. I believe you did this in order to get rid of the compiler error, not because copy semantics on that class are particularly useful. I'd recommend you delete that constructor again. If you really want copy semantics, have the constructor take its argument by reference to const.
class shm_server // cannot copy or move
{
std::atomic_bool done_ {};
public:
void
operator()()
{
this->run();
}
void
run()
{
using namespace std::chrono_literals;
while (!this->done_.load())
{
std::clog << std::this_thread::get_id() << " working..." << std::endl;
std::this_thread::sleep_for(1ms);
}
}
void
stop()
{
this->done_.store(true);
}
};
I have factored out the logic of the call operator into a named function for convenience. You don't need to do that but I'll use it later in the example.
Now we somehow have to make the run member function be executed on its own thread. If you write
shm_server server {};
std::thread worker {server}; // won't compile
the compiler won't let you do it as it – as you have conjectured yourself – would attempt to copy the server object which isn't copyable.
#Ben Voigt has suggested to wrap the server object into a std::reference_wrapper which is an object that behaves like a reference.
shm_server server {};
std::thread worker {std::ref(server)};
This works as intended and effectively passes a pointer to the std::thread constructor, rather than the actual server object.
However, I find that this is not the most straight-forward solution here. What you really want to do is run a member function of your server on a different thread. And std::thread's constructor lets you do just that.
shm_server server {};
std::thread worker {&shm_server::run, &server};
Here, I'm passing the address of the run member function and a pointer to the server object (that will be passed as the implicit this pointer) as argument. I have introduced the run function since the syntax might be less irritating. You can also pass the address of the call operator directly.
shm_server server {};
std::thread worker {&shm_server::operator(), &server};
Here is a complete example.
int
main()
{
using namespace std::chrono_literals;
std::clog << std::this_thread::get_id() << " starting up" << std::endl;
shm_server server {};
std::thread worker {&shm_server::operator(), &server};
//std::thread worker {std::ref(server)}; // same effect
//std::thread worker {&shm_server::run, &server}; // same effect
std::this_thread::sleep_for(10ms);
server.stop();
worker.join();
std::clog << std::this_thread::get_id() << " good bye" << std::endl;
}
Possible output:
140435324311360 starting up
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435306977024 working...
140435324311360 good bye
If you believe that a shm_server will only ever be useful if run on its own thread, you can also give it a std::thread as data member and have its constructor (or a dedicated start member function, if you prefer) start and its destructor join the thread.
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
class shm_server
{
std::atomic_bool done_ {};
std::thread worker_ {};
public:
shm_server()
{
this->worker_ = std::thread {&shm_server::run_, this};
}
~shm_server()
{
this->done_.store(true);
if (this->worker_.joinable())
this->worker_.join();
}
private:
void
run_()
{
using namespace std::chrono_literals;
while (!this->done_.load())
{
std::clog << std::this_thread::get_id() << " working..." << std::endl;
std::this_thread::sleep_for(1ms);
}
}
};
int
main()
{
using namespace std::chrono_literals;
std::clog << std::this_thread::get_id() << " starting up" << std::endl;
{
shm_server server {};
std::this_thread::sleep_for(10ms);
}
std::clog << std::this_thread::get_id() << " good bye" << std::endl;
}

How to join a std::thread from itself (in C++11)

I have a std::thread waiting and reading from a socket. And there is a pointer to this thread stored somewhere. But when something bad happens and the thread ends, I want it to call something that results in a function that will join this thread and then delete the pointer referring to it. (I have access to that pointer from within the thread)
I could do that in another thread but then that new thread becomes the problem.
You could create your thread in a detached state, and make your thread lifetime dependent a condition variable and switch a boolean state on finish.
#include <thread>
#include <iostream>
#include <unistd.h>
#include <condition_variable>
#include <mutex>
class A {
private:
void Threadfunction();
volatile bool class_running;
volatile bool thread_running;
std::condition_variable cv;
std::mutex mu;
public:
A();
~A();
void Stop();
};
A::A(){
class_running = true;
thread_running = false;
std::thread t(&A::Threadfunction,this);
t.detach();
}
A::~A(){
if(class_running) {this->Stop();}
}
void A::Stop() {
std::unique_lock<std::mutex> lk(mu);
class_running = false;
while(thread_running) {
cv.wait(lk);
}
std::cout << "Stop ended " << std::endl;
}
void A::Threadfunction(){
thread_running = true;
std::cout << "thread started " << std::endl;
while(class_running){
// Do something
}
thread_running = false;
cv.notify_one();
std::cout << "thread stopped " << std::endl;
}
int main(){
A a1;
A a2;
sleep(1);
std::cout << "a1.Stop() called " << std::endl;
a1.Stop();
sleep(1);
std::cout << "a2.Stop() not called but a2 goes out of scope and destructor is called " << std::endl;
}
Change your design so that you don't have this bizarre requirement. One simple solution is to use shared_ptrs to a control structure that owns the thread and has other status information as well. The thread can hold a shared_ptr to this control structure and use it to report its status to any other interested code. When nobody cares about this thread anymore, the last shared_ptr to this control structure will go away and it will be destroyed.

io_service run within thread

Why in this simple class if i use directly io.run() the function will be invoked otherwise if demand the run to other thread the print will not be invoked?
#include <iostream>
#include <boost/thread.hpp>
#include <boost/asio.hpp>
using namespace std;
class test
{
public:
test()
{
io.post(boost::bind(&test::print, this));
//io.run();
t = boost::thread(boost::bind(&boost::asio::io_service::run, &io));
}
void print()
{
cout << "test..." << endl;
}
private:
boost::thread t;
boost::asio::io_service io;
};
int main()
{
test();
return 0;
}
The thread object is being destroyed before allowing the io_service to completely run. The thread destructor documentation states:
[...] the programmer must ensure that the destructor is never executed while the thread is still joinable.
If BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE is defined, the program would abort as the thread destructor would call std::terminate().
If the io_service should run to completion, then consider joining the thread within Test's destructor. Here is a complete example that demonstrates synchronizing on the thread's completion:
#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
class test
{
public:
test()
{
io.post(boost::bind(&test::print, this));
t = boost::thread(boost::bind(&boost::asio::io_service::run, &io));
}
~test()
{
if (t.joinable())
t.join();
}
void print()
{
std::cout << "test..." << std::endl;
}
private:
boost::thread t;
boost::asio::io_service io;
};
int main()
{
test();
return 0;
}
Output:
test...
io_service::run() will complete all outstanding tasks and return when complete. If you don't call it, it will do nothing. If you do something like this:
boost::asio::io_service::work work(io);
Another thread will do this for you and run until you stop it one way or another.

Callback for arriving task in jobqueue?

I was wondering if anyone has any good design suggestions for a jobqueue that notifies a processJob() function when tasks > 0. I'm using Boost and c++ and just trying to get a general idea of such a design. Thanks.
I would run processJob() in a separate thread, which uses a "condition variable" to gate whether it's running; and when adding something to the queue, notifying that c.v.
The loop logic is something like:
boost::unique_lock<boost::mutex> lock(mymutex);
while (!terminate)
{
lock.lock();
while (!Q.empty())
jobCV.wait(lock);
pItem = Q.pop();
lock.unlock();
pItem->process();
}
Remember that adding items to the queue also needs to lock on the same mutex. Also, you'll need a test before that wait() for the signal that will set terminate; and the setting of that signal also needs to call notify() on the c.v.
If you already use boost library, it is convenient for you to just use boost::asio. an io_service object can be used to manage queue of jobs, since it guarantees the callbacks will be called in the order they are posted. and no hassle of locks if you only run io_service in one thread. Some sample code:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <cstdlib>
int job_number = 0;
struct Job
{
virtual void run() { std::cout << "job " << ++job_number << " done" << '\n'; }
virtual ~Job() {}
};
class Processor
{
private:
boost::asio::io_service ioserv_;
boost::asio::io_service::work work_;
boost::thread thread_;
public:
Processor() : ioserv_(), work_(ioserv_) {
}
void run() {
ioserv_.reset();
thread_ = boost::thread (boost::bind(&boost::asio::io_service::run, &ioserv_));
}
void stop() {
ioserv_.stop();
}
~Processor() {
stop();
if (thread_.get_id() != boost::thread::id())
thread_.join();
}
void processJob(boost::shared_ptr<Job> j)
{
j->run();
}
void addJob(boost::shared_ptr<Job> j)
{
ioserv_.post(boost::bind(&Processor::processJob, this, j));
}
};
int main()
{
Processor psr;
psr.run();
for (int i=0; i<10; ++i)
psr.addJob(boost::shared_ptr<Job>(new Job));
sleep(1);
return 0;
}