trouble SIGABRT in boost thread_group - c++

I got a trouble in boost::thread_group
boost::asio::io_service ioService;
boost::thread_group threadpool;
boost::asio::io_service::work work(ioService);
for (int i = 0; i < num_threads; i++) {
threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioService));
}
boost::thread *t_proxy = 0;
if (!without_proxy)
{
t_proxy = new boost::thread(boost::bind(&ThreadPool::w_proxy, this, proxy_link));
}
int task_size = tasks.size();
for (int i = 0; i < task_size; i++) {
boost::mutex::scoped_lock lock(_mutex);
working_threads++;
ioService.post(boost::bind(&ThreadPool::thread_worker, this));
tasks.pop_front();
ioService.stop();
if (t_proxy)
{
t_proxy->join();
}
threadpool.join_all();
&ThreadPool::w_proxy - thread, which checks proxy in a background and saves it into common list
&ThreadPool::thread_worker - worker function, which uses proxy from the common list and does some functions
tasks vector with task list
_mutex - boost::mutex used for sync proxy list and thread_worker result
trouble point:
in process I got a SIGABRT in string
t_proxy->join();
or in
threadpool.join_all();
I`ve tried to add w_proxy in general thread_group, and I got same trouble
threadpool.join_all();
I have a traceback in condition_variable.hpp
The failed function is condition_variable::wait in line
res = pthread_cond_wait(&cond,&internal_mutex);
could you help me with it?

Related

How to check whether tasks in io_service are completed?

I have a question about boost::io_service.
I have a set of tasks that I can run concurrently. After running all of them, I need to run another set of tasks concurrently. However first set has to be completed before starting to run the second set. This means I need to make sure that all the jobs submitted to io_service is completed before starting to schedule to second set.
I can implement it by keeping some kind of counter and add a busy loop but it does not look very efficient. So, I wanted to checked whether someone has a better idea or not. Following is a dummy code that I was using to experiment.
Thank you in advance!
#include <cstdio>
#include <iostream>
#include <unistd.h>
#include <boost/asio/io_service.hpp>
#include <boost/bind.hpp>
#include <boost/thread/thread.hpp>
const size_t numTasks = 100000;
void print_counter(const size_t id)
{
if (id + 1 == numTasks) {
printf("sleeping for %ld\n", id);
sleep(15);
}
printf("%ld\n", id);
}
int main(int argc, char** argv)
{
using namespace std;
using namespace boost;
asio::io_service io_service;
asio::io_service::work work(io_service);
const size_t numWorker = 4;
boost::thread_group workers;
for(size_t i = 0; i < numWorker; ++i) {
workers.create_thread(boost::bind(&asio::io_service::run, &io_service));
}
for(size_t i = 0; i < numTasks; ++i) {
io_service.post(boost::bind(print_counter, i));
}
// TODO: wait until all the tasks are done above
for(size_t i = 0; i < numTasks; ++i) {
io_service.post(boost::bind(print_counter, i));
}
// TODO: wait until all the tasks are done above
// ...
// Finally stop the service
io_service.stop();
workers.join_all();
return 0;
}
Your main problem is that all sets of your tasks are processed by the same instance of io_service. Function io_service::run returns where there is no tasks to be processed. Destructor of io_service::work informs io_service object that run can return where there are no pending tasks in queue to be performed. You can post all tasks from first set, then destroyed work and wait until io_service::run returns, then create again work object, post tasks from the next set and delete work, and so on. To do it just write helper class which may look like something below:
class TasksWaiter
{
public:
TasksWaiter(int numOfThreads)
{
work = std::make_unique<boost::asio::io_service::work>(io_service);
for(size_t i = 0; i < numOfThreads; ++i) {
workers.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
}
}
~TasksWaiter() {
work.reset();
workers.join_all();
}
template<class F>
void post(F f) {
io_service.post(f);
}
boost::thread_group workers;
boost::asio::io_service io_service;
std::unique_ptr<boost::asio::io_service::work> work;
};
int main()
{
{
TasksWaiter w1{4};
for (int i = 0; i < numTasks; ++i)
w1.post(boost::bind(print_counter,i));
// work in w1 is destroyed, then io_service::run ends
// when there are no tasks to be performed
}
printf("wait here");
{
TasksWaiter w1{4};
for (int i = 0; i < numTasks; ++i)
w1.post(boost::bind(print_counter,i));
}
}
a few remarks:
in constructor pool of threads are created
in destructor work is deleted, so io_service::run returns only if there are no pending tasks
functionality of destructor can be wrapped into a member function - e.g. wait, then you don't have to use {} scope to wait for your tasks.
From the io_service::run documentation:
The run() function blocks until all work has finished and there are no more handlers to be dispatched, or until the io_context has been stopped.
Also, from the io_context::work constructor documentation:
The constructor is used to inform the io_context that some work has begun. This ensures that the io_context object's run() function will not exit while the work is underway.
[Emphasis mine]
In short, if the run function returns and stopped returns false, then all work has been finished.

How to Control Thread Pool in Boost/C++ Implementation

I'm working on a really basic application to teach myself about thread pools and being able to control them in c++ using boost.
What I'm trying to do is to be able to issue a command that can pause/restart one of the thread pools that are being used.
void printStuff(int x){
while(true){
std::cout <<" Hi from thread 1 in group " << x << std::endl;
boost::this_thread::sleep( boost::posix_time::milliseconds(1000) );
}
}
void pstwo(int x){
while(true){
std::cout <<" Hi from thread 2 in group " << x << std::endl;
boost::this_thread::sleep( boost::posix_time::milliseconds(1500) );
}
}
int main()
{
boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service);
boost::asio::io_service io_service2;
boost::asio::io_service::work work2(io_service2);
boost::thread_group threads;
boost::thread_group threadsTwo;
for (std::size_t i = 0; i < 2; ++i)
threads.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
for (std::size_t i = 0; i < 2; ++i)
threadsTwo.create_thread(boost::bind(&boost::asio::io_service::run, &io_service2));
io_service.post(boost::bind(printStuff,1));
io_service.post(boost::bind(pstwo,1));
io_service2.post(boost::bind(printStuff,2));
io_service2.post(boost::bind(pstwo,2));
boost::this_thread::sleep( boost::posix_time::milliseconds(10000));
io_service.stop();
std::cout<<"------------------"<<std::endl;
boost::this_thread::sleep( boost::posix_time::milliseconds(10000));
io_service.run();
io_service2.stop();
std::cout<<"-----------------"<<std::endl;
boost::this_thread::sleep( boost::posix_time::milliseconds(10000));
io_service.stop();
threads.join_all();
threadsTwo.join_all();
return 0;
}
The calls to io_service.stop do not actually stop any of the threads in the thread pool.
The problem, why the threads don't stop, is because when you stop io_service, it actually stops executing the event loop as soon as it is possible. But the current event is infinite loop. I think you should use for example atomic_bool to set some kind of "stopping" state and to check this state inside the threads.
By the way, you should use io_service.reset() between stop() and run().

Do I need to implement blocking when using boost::asio?

My question is, if I run io_service::run () on multiple threads, do I need to implement blocking on these asynchronous functions?
example:
int i = 0;
int j = 0;
void test_timer(boost::system::error_code ec)
{
//I need to lock up here ?
if (i++ == 10)
{
j = i * 10;
}
timer.expires_at(timer.expires_at() + boost::posix_time::milliseconds(500));
timer.async_wait(&test_timer);
}
void threadMain()
{
io_service.run();
}
int main()
{
boost::thread_group workers;
timer.async_wait(&test_timer);
for (int i = 0; i < 5; i++){
workers.create_thread(&threadMain);
}
io_service.run();
workers.join_all();
return 0;
}
The definition of async is that it is non-blocking.
If you mean to ask "do I have to synchronize access to shared objects from different threads" - that question is unrelated and the answer depends on the thread-safety documented for the object you are sharing.
For Asio, basically (rough summary) you need to synchronize concurrent access (concurrent as in: from multiple threads) to all types except boost::asio::io_context¹,².
Your Sample
Your sample uses multiple threads running the io service, meaning handlers run on any of those threads. This means that effectively you're sharing the globals and indeed they need protection.
However Because your application logic (the async call chain) dictates that only one operation is ever pending, and the next async operation on the shared timer object is always scheduled from within that chain, the access is logically all from a single thread (called an implicit strand. See Why do I need strand per connection when using boost::asio?
The simplest thing that would work:
Logical Strand
Live On Coliru
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>
boost::asio::io_service io_service;
boost::asio::deadline_timer timer { io_service };
struct state_t {
int i = 0;
int j = 0;
} state;
void test_timer(boost::system::error_code ec)
{
if (ec != boost::asio::error::operation_aborted) {
{
if (state.i++ == 10) {
state.j = state.i * 10;
if (state.j > 100)
return; // stop after 5 seconds
}
}
timer.expires_at(timer.expires_at() + boost::posix_time::milliseconds(50));
timer.async_wait(&test_timer);
}
}
int main()
{
boost::thread_group workers;
timer.expires_from_now(boost::posix_time::milliseconds(50));
timer.async_wait(&test_timer);
for (int i = 0; i < 5; i++){
workers.create_thread([] { io_service.run(); });
}
workers.join_all();
std::cout << "i = " << state.i << std::endl;
std::cout << "j = " << state.j << std::endl;
}
Note I removed the io_service::run() from the main thread as it is redundant with the join() (unless you really wanted 6 threads running the handlers, not 5).
Prints
i = 11
j = 110
Caveat
There's a pitfall lurking here. Say, you didn't want to bail at a fixed number, like I did, but want to stop, you'd be tempted to do:
timer.cancel();
from main. That's not legal, because the deadline_timer object is not thread safe. You'd need to either
use a global atomic_bool to signal the request for termination
post the timer.cancel() on the same strand as the timer async chain. However, there is only an explicit strand, so you can't do it without changing the code to use an explicit strand.
More Timers
Let's complicate things by having two timers, with their own implicit strands. This means access to the timer instances still need not be synchronized, but access to i and j does need to be.
Note In this demo I use synchronized_value<> for elegance. You can write similar logic manually using mutex and lock_guard.
Live On Coliru
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/thread/synchronized_value.hpp>
#include <iostream>
boost::asio::io_service io_service;
struct state {
int i = 0;
int j = 0;
};
boost::synchronized_value<state> shared_state;
struct TimerChain {
boost::asio::deadline_timer _timer;
TimerChain() : _timer{io_service} {
_timer.expires_from_now(boost::posix_time::milliseconds(50));
resume();
}
void resume() {
_timer.async_wait(boost::bind(&TimerChain::test_timer, this, _1));
};
void test_timer(boost::system::error_code ec)
{
if (ec != boost::asio::error::operation_aborted) {
{
auto state = shared_state.synchronize();
if (state->i++ == 10) {
state->j = state->i * 10;
}
if (state->j > 100) return; // stop after some iterations
}
_timer.expires_at(_timer.expires_at() + boost::posix_time::milliseconds(50));
resume();
}
}
};
int main()
{
boost::thread_group workers;
TimerChain timer1;
TimerChain timer2;
for (int i = 0; i < 5; i++){
workers.create_thread([] { io_service.run(); });
}
workers.join_all();
auto state = shared_state.synchronize();
std::cout << "i = " << state->i << std::endl;
std::cout << "j = " << state->j << std::endl;
}
Prints
i = 12
j = 110
Adding The Explicit Strands
Now it's pretty straight-forward to add them:
struct TimerChain {
boost::asio::io_service::strand _strand;
boost::asio::deadline_timer _timer;
TimerChain() : _strand{io_service}, _timer{io_service} {
_timer.expires_from_now(boost::posix_time::milliseconds(50));
resume();
}
void resume() {
_timer.async_wait(_strand.wrap(boost::bind(&TimerChain::test_timer, this, _1)));
};
void stop() { // thread safe
_strand.post([this] { _timer.cancel(); });
}
// ...
Live On Coliru
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/thread/synchronized_value.hpp>
#include <iostream>
boost::asio::io_service io_service;
struct state {
int i = 0;
int j = 0;
};
boost::synchronized_value<state> shared_state;
struct TimerChain {
boost::asio::io_service::strand _strand;
boost::asio::deadline_timer _timer;
TimerChain() : _strand{io_service}, _timer{io_service} {
_timer.expires_from_now(boost::posix_time::milliseconds(50));
resume();
}
void resume() {
_timer.async_wait(_strand.wrap(boost::bind(&TimerChain::test_timer, this, _1)));
};
void stop() { // thread safe
_strand.post([this] { _timer.cancel(); });
}
void test_timer(boost::system::error_code ec)
{
if (ec != boost::asio::error::operation_aborted) {
{
auto state = shared_state.synchronize();
if (state->i++ == 10) {
state->j = state->i * 10;
}
}
// continue indefinitely
_timer.expires_at(_timer.expires_at() + boost::posix_time::milliseconds(50));
resume();
}
}
};
int main()
{
boost::thread_group workers;
TimerChain timer1;
TimerChain timer2;
for (int i = 0; i < 5; i++){
workers.create_thread([] { io_service.run(); });
}
boost::this_thread::sleep_for(boost::chrono::seconds(10));
timer1.stop();
timer2.stop();
workers.join_all();
auto state = shared_state.synchronize();
std::cout << "i = " << state->i << std::endl;
std::cout << "j = " << state->j << std::endl;
}
Prints
i = 400
j = 110
¹ (or using the legacy name boost::asio::io_service)
² lifetime mutations are not considered member operations in this respect (you have to manually synchronize construction/destruction of shared objects even for thread-safe objects)

Using Boost threads and io_service to create a threadpool

I have looked around Stack Overflow and there have been a few really good answers on this, (my code is actually based on this answer here) but for some reason I am getting weird behavior - in that thread_func should be called ls1 times, but it is only running between 0 and 2 times before the threads exit. It seems like ioService.stop() is cutting off queued jobs before they are completed, but from what I understand this should not happen. Here is the relevant code snippet:
boost::asio::io_service ioService;
boost::asio::io_service::work work(ioService);
boost::thread_group threadpool;
for (unsigned t = 0; t < num_threads; t++)
{
threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioService));
}
//Iterate over the dimensions of the matrices
for (unsigned i = 0; i < ls1; i++)
{
ioService.post(boost::bind(&thread_func,i, rs1, rs2, ls2, arr, left_arr, &result));
}
ioService.stop();
threadpool.join_all();
Any help would be greatly appreciated, thanks!
io_service::stop() causes all invocations of run() or run_one() to return as soon as possible. It does not remove any outstanding handlers that are already queued into the io_service. When io_service::stop() is invoked, the threads in threadpool will return as soon as possible, causing each thread of execution to be complete.
As io_service::post() will return immediately after requesting that the io_service invoke the handler, it is non-deterministic as to how many posted handlers will be invoked by threads in threadpool before the io_service is stopped.
If you wish for thread_func to be invoked ls1 times, then one simple alternative is to reorganize the code so that work is added to the io_service before the threadpool services it, and then the application lets the io_service run to completion.
boost::asio::io_service ioService;
// Add work to ioService.
for (unsigned i = 0; i < ls1; i++)
{
ioService.post(boost::bind(
&thread_func,i, rs1, rs2, ls2, arr, left_arr, &result));
}
// Now that the ioService has work, use a pool of threads to service it.
boost::thread_group threadpool;
for (unsigned t = 0; t < num_threads; t++)
{
threadpool.create_thread(boost::bind(
&boost::asio::io_service::run, &ioService));
}
// Once all work has been completed (thread_func invoked ls1 times), the
// threads in the threadpool will be completed and can be joined.
threadpool.join_all();
If you're expecting thread_func to be called ls1 times, then you should wait until it is actually called ls1 times before stopping io_service. As written, stop() may be called before any of the threads had a chance to have been scheduled even.
There are many ways to wait for that condition. For example you could use a condition variable:
#include <boost/asio.hpp>
#include <boost/thread.hpp>
unsigned num_threads = 10, ls1=11;
int result = 0;
boost::mutex m;
boost::condition_variable cv;
void thread_func(unsigned , int* result) {
/* do stuff */
{
boost::lock_guard<boost::mutex> lk(m);
++*result;
}
cv.notify_one();
}
int main()
{
boost::asio::io_service ioService;
boost::asio::io_service::work work(ioService);
boost::thread_group threadpool;
for (unsigned t = 0; t < num_threads; t++)
threadpool.create_thread(boost::bind(&boost::asio::io_service::run,
&ioService));
for (unsigned i = 0; i < ls1; i++)
ioService.post(boost::bind(&thread_func,i,&result));
{
boost::unique_lock<boost::mutex> lk(m);
cv.wait(lk, []{return result == ls1; });
}
ioService.stop();
threadpool.join_all();
std::cout << "result = " << result << '\n';
}

Is boost::io_service::post thread safe?

Is it thread safe to post new handlers from within a handler?
I.e. Can threads that called the io_service::run() post new Handlers to the same io_service?
Thanks
It is safe to post handlers from within a handler for a single instance of an io_service according to the documentation.
Thread Safety
Distinct objects: Safe.
Shared objects: Safe, with the exception that calling reset() while
there are unfinished run(), run_one(),
poll() or poll_one() calls results in
undefined behaviour.
I think it's not because the following code didn't return 3000000 and I didn't see mutex synching the internal queue of io_service neither a lock-free queue.
#include <boost/asio/io_service.hpp>
#include <boost/thread.hpp>
#include <boost/thread/detail/thread_group.hpp>
#include <memory>
void postInc(boost::asio::io_service *service, std::atomic_int *counter) {
for(int i = 0; i < 100000; i++) service->post([counter] { (*counter)++; });
}
int main(int argc, char **argv)
{
std::atomic_int counter(0);
{
boost::asio::io_service service;
boost::asio::io_service::work working(service);
boost::thread_group workers;
for(size_t i = 0; i < 10;++i) workers.create_thread(boost::bind(&boost::asio::io_service::run, &service));
boost::thread_group producers;
for (int it = 0; it < 30; it++)
{
producers.add_thread(new boost::thread(boost::bind(postInc,&service,&counter)));
}
producers.join_all();
std::cout << "producers ended" << std::endl;
service.stop();
workers.join_all();
}
std::cout << counter.load();
char c; std::cin >> c;
return 0;
}