boost::asio::io_service::strand refuses to go away - c++

I am using strand to serialize certain processing within some objects. However, when the object dies, the strand element somehow refuses go away. Like a soul in purgatory, it manages to live in memory and causes memory usage to increase over days. I have managed to replicate the problem in a sample code.
I am creating 5 families, each with one parent and a child. The parent object contains the child and a strand object to ensure the processing happens in serial fashion. Each family is issued 3 processing tasks and they do it in the right order irrespective of the thread they run on. I am taking memory heap snapshot in VC++ before and after the object creation and processing. The snapshot comparison shows that the strand alone manages to live even after Parent and Child object have been destroyed.
How do I ensure strand object is destroyed? Unlike the sample program, my application runs for years without shutdown. I will be stuck with millions of zombie strand objects within a month.
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio/strand.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
#include <boost/asio/yield.hpp>
#include <boost/log/attributes/current_thread_id.hpp>
#include <iostream>
boost::mutex mtx;
class Child : public boost::noncopyable, public boost::enable_shared_from_this<Child>
{
int _id;
public:
Child(int id) : _id(id) {}
void process(int order)
{
boost::this_thread::sleep_for(boost::chrono::seconds(2));
boost::lock_guard<boost::mutex> lock(mtx);
std::cout << "Family " << _id << " processing order " << order << " in thread " << std::hex << boost::this_thread::get_id() << std::endl;
}
};
class Parent : public boost::noncopyable, public boost::enable_shared_from_this<Parent>
{
boost::shared_ptr<Child> _child;
boost::asio::io_service::strand _strand;
public:
Parent(boost::asio::io_service& ioS, int id) : _strand(ioS)
{
_child = boost::make_shared<Child>(id);
}
void process()
{
for (int order = 1; order <= 3; order++)
{
_strand.post(boost::bind(&Child::process, _child, order));
}
}
};
int main(int argc, char* argv[])
{
boost::asio::io_service ioS;
boost::thread_group threadPool;
boost::asio::io_service::work work(ioS);
int noOfCores = boost::thread::hardware_concurrency();
for (int i = 0; i < noOfCores; i++)
{
threadPool.create_thread(boost::bind(&boost::asio::io_service::run, &ioS));
}
std::cout << "Take the first snapshot" << std::endl;
boost::this_thread::sleep_for(boost::chrono::seconds(10));
std::cout << "Creating families" << std::endl;
for (int family = 1; family <= 5; family++)
{
auto obj = boost::make_shared<Parent>(ioS,family);
obj->process();
}
std::cout << "Take the second snapshot after all orders are processed" << std::endl;
boost::this_thread::sleep_for(boost::chrono::seconds(60));
return 0;
}
The output looks like this:
Take the first snapshot
Creating families
Take the second snapshot after all orders are processed
Family 3 processing order 1 in thread 50c8
Family 1 processing order 1 in thread 5e38
Family 4 processing order 1 in thread a0c
Family 5 processing order 1 in thread 47e8
Family 2 processing order 1 in thread 5f94
Family 3 processing order 2 in thread 46ac
Family 2 processing order 2 in thread 47e8
Family 5 processing order 2 in thread a0c
Family 1 processing order 2 in thread 50c8
Family 4 processing order 2 in thread 5e38
Family 2 processing order 3 in thread 47e8
Family 4 processing order 3 in thread 5e38
Family 1 processing order 3 in thread 50c8
Family 5 processing order 3 in thread a0c
Family 3 processing order 3 in thread 46ac
I took the first heap snapshot before creating families. I took the second snapshot few seconds after all the 15 lines were printed (5 familes X 3 tasks). The heap comparison shows the following:
All the Parent and Child objects have gone away, but all the 5 strand objects lives on...
Edit: For those who don't understand shared_ptr, the objects don't die at the end of the loop. Since the reference of the child has been passed to 3 process tasks, at least child live a charmed life until all the tasks are completed for a given family. Once all references are cleared, Child object will die.

That's by design. A strand uses a pool of mutexes which live until the io_service dies.
But the pool size is limited currently to 193.
So you should not see more than 193 of those hanging around. See also issue #259.

Related

How to let thread wait for specific other thread to unlock data c++

Lets say I have one thread that continuously updates a certain object. During the update, the object must be locked for thread safety.
Now the second thread is more of an event kind of operation. If such a thread is spawned, I'd like the running update to finish it's call and then immediately perform the event operation.
What I absolutely want to avoid is a situation where the event thread needs to wait until it gets lucky to be given computation time at a specific time the update thread doesn't lock up the data it needs to access.
Is there any way I could use the threading/mutex tools in c++ to accomplish this? Or should I save the to-be-done operation in an unlocked var and perform the operation on the update thread?
//// System.h
#pragma once
#include <mutex>
#include <iostream>
#include <chrono>
#include <thread>
class System {
private:
int state = 0;
std::mutex mutex;
public:
void update();
void reset(int e);
};
//////// System.cpp
#include "System.h"
void System::update() {
std::lock_guard<std::mutex> guard(mutex);
state++;
std::cout << state << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void System::reset(int e) {
std::lock_guard<std::mutex> guard(mutex);
state = e;
std::cout << state << std::endl;
}
////// ThreadTest.h
#pragma once
#include <iostream>
#include "System.h"
void loop_update(System& system);
void reset_system(System& system);
int main();
////// ThreadTest.cpp
#include "ThreadTest.h"
void loop_update(System& system) {
while (true) system.update();
};
void reset_system(System& system) {
system.reset(0);
};
int main()
{
System system;
std::thread t1 = std::thread(loop_update, std::ref(system));
int reset = 0;
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(10));
std::cout << "Reset" << std::endl;
reset_system(system);
}
}
Example gives following output. You can clearly see a huge delay in the actual update.
1
...
10
Reset
11
...
16
0
1
...
10
Reset
11
...
43
0
1
If I understand you correctly, you have 2 threads using the same mutex. However, you want one thread to get a higher preference than the other to get the actual lock.
As far as I know, there ain't a way to ensure preference using the native tools. You can work around it, if you don't mind the code of both threads knowing about it.
For example:
std::atomic<int> shouldPriorityThreadRun{0};
auto priorityThreadCode = [&shouldPriorityThreadRun](){
++shouldPriorityThreadRun;
auto lock = std::unique_lock{mutex};
doMyStuff();
--shouldPriorityThreadRun;
};
auto backgroundThreadCode = [&shouldPriorityThreadRun](){
while (true)
{
if (shouldPriorityThreadRun == 0)
{
auto lock = std::unique_lock{mutex};
doBackgroundStuff();
}
else
std::this_thread::yield();
}
};
If you have multiple priority threads, those can't have priority over each other.
If you don't like the yield, you could do fancier stuff with std::condition_variable, so you can inform other threads that the mutex is available. However, I believe it's good enough.
it should already work with your current approach.
The mutex is locking concurrent access to your data, so you can lock it within the first thread to update the data.
If the event routine / your second thread comes to execution, it always has to check if the mutex is unlocked. If the mutex is unlocked - and only then, you can lock the mutex and perform the tasks of the second thread.
If I understand your code correctly (i am not a c++ expert), the std::lock_guard<std::mutex> guard(mutex); seems to be locking the mutex the entire time of the update function...
And therefore other threads merely have time to access the mutex.
When the update thread finish the job, it needs to unlock the mutex before entering the sleep state, then the reset thread could have a chance to take the lock without any delay. I also tried running your codes on my machine and observe it's still waiting for the lock. I don't know when it gets lucky to take the lock. I think in this case it's an UB
2
3
4
5
6
7
8
9
10
Reset
11
12
13
14
15
16
17
18...
void System::update() {
mutex.lock();
state++;
std::cout << state << std::endl;
mutex.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void System::reset(int e) {
mutex.lock();
state = e;
std::cout << state << std::endl;
mutex.unlock();
}

Understanding how multithreading works with Boost io_service

I'm learning multithreading and Boost libraries (Asio in particular) and I'm having a hard time understanding how the following code works (slightly modified from Boost.org tutorials)
#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
class printer
{
public:
printer(boost::asio::io_service& io)
: timer1_(io, boost::posix_time::seconds(1)),
timer2_(io, boost::posix_time::seconds(1)),
count_(0)
{
timer1_.async_wait(boost::bind(&printer::print1, this));
timer2_.async_wait(boost::bind(&printer::print2, this));
}
~printer()
{
std::cout << "Final count is " << count_ << std::endl;
}
void print1()
{
if (count_ < 10)
{
std::cout << "Timer 1: " << count_ << std::endl;
++count_;
timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(2));
timer1_.async_wait(boost::bind(&printer::print1, this));
}
}
void print2()
{
if (count_ < 10)
{
std::cout << "Timer 2: " << count_ << std::endl;
++count_;
timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(2));
timer2_.async_wait(boost::bind(&printer::print2, this));
}
}
private:
boost::asio::deadline_timer timer1_;
boost::asio::deadline_timer timer2_;
int count_;
};
void saysomething()
{
std::string whatyasay;
std::cin >> whatyasay;
std::cout << "You said " << whatyasay << std::endl;
}
int main()
{
boost::asio::io_service io;
printer p(io);
boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
io.run();
std::cout << "Hey there\n";
t.join();
return 0;
}
Which results in the following output
Timer 1: 0
Timer 2: 1
Timer 1: 2
Timer 2: 3
Timer 1: 4
Timer 2: 5
Timer 1: 6
Timer 2: 7
Timer 1: 8
Timer 2: 9
Hey there
Final count is 10
What I would've expected from this code was that thread t would be in charge of running the io_service, meaning that other operations could take place in the meantime.
Instead, the code behaves as usual, aka, io.run "blocks" the code flow until the timers inside the printer object stop launching async_waits, so "hey there" is only printed after the timers are not working anymore.
But that's not all: from my understanding, io_services don't stop running after the run() method is called as long as there's work associated to them (be it a work object or, in this case, timers). With that said, since the thread is associated to the io_service, I wonder why the io_service would stop running in the first place: after all, the thread is "linked" to the io_service and keeps on running on its own; this is obviously linked to the fact that I clearly didn't understand what this thread is doing in the first place.
Things got even more complicated when I added the "saysomething" method into the pot: I wanted to be able to write something and having that string printed WHILE the 2 timers kept working. The code I used was the following:
int main()
{
boost::asio::io_service io;
printer p(io);
boost::thread t(&saysomething);
io.run();
std::cout << "Hey there\n";
t.join();
return 0;
}
With the following result:
Timer 1: 0
Timer 2: 1
Timer 1: 2
Timer 2: 3
Timer 1: 4
Timer 2: 5
Timer 1: 6
Timer 2: 7
ghg //<--- my input
You said ghg
Timer 1: 8
Timer 2: 9
Hey there
Final count is 10
It works fine, but now that there is no thread associated to the io_service, what was its purpose in the first place?
To sum up my 3 questions are:
Why isn't the "Hey there" string immediately printed rather than waiting for the io_service to stop running?
How exactly does the io_service stop running if a thread is linked to it, which should be equivalent to the io_service having work to do?
Since the thread wasn't allowing the "code flow" to move forward, and linking said thread to my method instead of the io_service didn't cause any error, what was the purpose of that thread in the first place?
Why isn't the "Hey there" string immediately printed rather than waiting for the io_service to stop running?
main's thread also blocks on the io_service before printing, so "Hey there" doesn't print until the service stops.
How exactly does the io_service stop running if a thread is linked to it, which should be equivalent to the io_service having work to do?
The thread is not what's keeping the io_service alive, the timer tasks are. The io_service is actually the one keeping the thread alive here. The work the service has is waiting on the timers, so until the timers expire, the service has work to do.
Since the thread wasn't allowing the "code flow" to move forward, and linking said thread to my method instead of the io_service didn't cause any error, what was the purpose of that thread in the first place?
The purpose of calling run from a thread is to donate that calling thread to the io_service. Until run exits, the service owns that thread, and that thread is part of the service's thread pool. Any task you post to the service may be handed to that thread while it is in the service's pool. When you added the second thread, that second thread wasn't interacting with the service at all because it didn't call run. Thus, it's not part of the service's thread pool.

boost::fiber scheduling - when and how

According to the documentation
the currently-running fiber retains control until it invokes some
operation that passes control to the manager
I can think about only one operation - boost::this_fiber::yield which may cause control switch from fiber to fiber. However, when I run something like
bf::fiber([](){std::cout << "Bang!" << std::endl;}).detach();
bf::fiber([](){std::cout << "Bung!" << std::endl;}).detach();
I get output like
Bang!Bung!
\n
\n
Which means control was passed between << operators from one fiber to another. How it could happen? Why? What is the general definition of controll passing from fiber to fiber in the context of boost::fiber library?
EDIT001:
Cant get away without code:
#include <boost/fiber/fiber.hpp>
#include <boost/fiber/mutex.hpp>
#include <boost/fiber/barrier.hpp>
#include <boost/fiber/algo/algorithm.hpp>
#include <boost/fiber/algo/work_stealing.hpp>
namespace bf = boost::fibers;
class GreenExecutor
{
std::thread worker;
bf::condition_variable_any cv;
bf::mutex mtx;
bf::barrier barrier;
public:
GreenExecutor() : barrier {2}
{
worker = std::thread([this] {
bf::use_scheduling_algorithm<bf::algo::work_stealing>(2);
// wait till all threads joining the work stealing have been registered
barrier.wait();
mtx.lock();
// suspend main-fiber from the worker thread
cv.wait(mtx);
mtx.unlock();
});
bf::use_scheduling_algorithm<bf::algo::work_stealing>(2);
// wait till all threads have been registered the scheduling algorithm
barrier.wait();
}
template<typename T>
void PostWork(T&& functor)
{
bf::fiber {std::move(functor)}.detach();
}
~GreenExecutor()
{
cv.notify_all();
worker.join();
}
};
int main()
{
GreenExecutor executor;
std::this_thread::sleep_for(std::chrono::seconds(1));
int i = 0;
for (auto j = 0ul; j < 10; ++j) {
executor.PostWork([idx {++i}]() {
auto res = pow(sqrt(sin(cos(tan(idx)))), M_1_PI);
std::cout << idx << " - " << res << std::endl;
});
}
while (true) {
boost::this_fiber::yield();
}
return 0;
}
Output
2 - 1 - -nan
0.503334 3 - 4 - 0.861055
0.971884 5 - 6 - 0.968536
-nan 7 - 8 - 0.921959
0.9580699
- 10 - 0.948075
0.961811
Ok, there were a couple of things I missed, first, my conclusion was based on misunderstanding of how stuff works in boost::fiber
The line in the constructor mentioned in the question
bf::use_scheduling_algorithm<bf::algo::work_stealing>(2);
was installing the scheduler in the thread where the GreenExecutor instance was created (in the main thread) so, when launching two worker fibers I was actually initiating two threads which are going to process submitted fibers which in turn would process these fibers asynchronously thus mixing the std::cout output. No magic, everything works as expected, the boost::fiber::yield still is the only option to pass control from one fiber to another

How can I safely terminate worker threads when they are complete?

I was trying to implement a master-worker model using the C++ 11 synchronization features for practice. The model uses a std::queue object along with a condition variable and some mutexes. The master thread puts tasks in the queue and the worker threads pops a task off the queue and "processes" them.
The code I have works properly (unless I've missed some race conditions) when I don't terminate the worker threads. However, the program never ends until you manually terminate it with Ctrl+C. I have some code to terminate the workers after the master thread finishes. Unfortunately, this doesn't work properly as it skips the last task on some execution runs.
So my question:
Is it possible to safely and properly terminate worker threads after all tasks have been processed?
This was just a proof of concept and I'm new to C++ 11 features so I apologize for my style. I appreciate any constructive criticism.
EDIT: nogard has kindly pointed out that this implementation of the model makes it quite complicated and showed me that what I'm asking for is pointless since a good implementation will not have this problem. Thread pools are the way to go in order to implement this properly. Also, I should be using an std::atomic instead of a normal boolean for worker_done (Thanks Jarod42).
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
#include <mutex>
#include <queue>
#include <condition_variable>
//To sleep
#include <unistd.h>
struct Task
{
int taskID;
};
typedef struct Task task;
//cout mutex
std::mutex printstream_accessor;
//queue related objects
std::queue<task> taskList;
std::mutex queue_accessor;
std::condition_variable cv;
//worker flag
bool worker_done = false;
//It is acceptable to call this on a lock only if you poll - you will get an inaccurate answer otherwise
//Will return true if the queue is empty, false if not
bool task_delegation_eligible()
{
return taskList.empty();
}
//Thread safe cout function
void safe_cout(std::string input)
{
// Apply a stream lock and state the calling thread information then print the input
std::unique_lock<std::mutex> cout_lock(printstream_accessor);
std::cout << "Thread:" << std::this_thread::get_id() << " " << input << std::endl;
}//cout_lock destroyed, therefore printstream_accessor mutex is unlocked
void worker_thread()
{
safe_cout("worker_thread() initialized");
while (!worker_done)
{
task getTask;
{
std::unique_lock<std::mutex> q_lock(queue_accessor);
cv.wait(q_lock,
[]
{ //predicate that will check if available
//using a lambda function to apply the ! operator
if (worker_done)
return true;
return !task_delegation_eligible();
}
);
if (!worker_done)
{
//Remove task from the queue
getTask = taskList.front();
taskList.pop();
}
}
if (!worker_done)
{
//process task
std::string statement = "Processing TaskID:";
std::stringstream convert;
convert << getTask.taskID;
statement += convert.str();
//print task information
safe_cout(statement);
//"process" task
usleep(5000);
}
}
}
/**
* master_thread():
* This thread is responsible for creating task objects and pushing them onto the queue
* After this, it will notify all other threads who are waiting to consume data
*/
void master_thread()
{
safe_cout("master_thread() initialized");
for (int i = 0; i < 10; i++)
{
//Following 2 lines needed if you want to don't want this thread to bombard the queue with tasks before processing of a task can be done
while (!task_delegation_eligible() ) //task_eligible() is true IFF queue is empty
std::this_thread::yield(); //yield execution to other threads (if there are tasks on the queue)
//create a new task
task newTask;
newTask.taskID = (i+1);
//lock the queue then push
{
std::unique_lock<std::mutex> q_lock(queue_accessor);
taskList.push(newTask);
}//unique_lock destroyed here
cv.notify_one();
}
safe_cout("master_thread() complete");
}
int main(void)
{
std::thread MASTER_THREAD(master_thread); //create a thread object named MASTER_THREAD and have it run the function master_thread()
std::thread WORKER_THREAD_1(worker_thread);
std::thread WORKER_THREAD_2(worker_thread);
std::thread WORKER_THREAD_3(worker_thread);
MASTER_THREAD.join();
//wait for the queue tasks to finish
while (!task_delegation_eligible()); //wait if the queue is full
/**
* Following 2 lines
* Terminate worker threads => this doesn't work as expected.
* The model is fine as long as you don't try to stop the worker
* threads like this as it might skip a task, however this program
* will terminate
*/
worker_done = true;
cv.notify_all();
WORKER_THREAD_1.join();
WORKER_THREAD_2.join();
WORKER_THREAD_3.join();
return 0;
}
Thanks a lot
There is visibility issue in your program: the change of worker_done flag made in one thread might not be observed by worker thread. In order to guarantee that the results of one action are observable to a second action, then you have to use some form of synchronization to make sure that the second thread sees what the first thread did.
To fix this issue you can use atomic as proposed by Jarod42.
If you do this program for practicing it's fine, but for the real applications you could profit from existing thread pool, which would greatly simplify your code.

Setting limit on post queue size with Boost Asio?

I'm using boost::asio::io_service as a basic thread pool. Some threads get added to io_service, the main thread starts posting handlers, the worker threads start running the handlers, and everything finishes. So far, so good; I get a nice speedup over single-threaded code.
However, the main thread has millions of things to post. And it just keeps on posting them, much faster than the worker threads can handle them. I don't hit RAM limits, but it's still kind of silly to be enqueuing so many things. What I'd like to do is have a fixed-size for the handler queue, and have post() block if the queue is full.
I don't see any options for this in the Boost ASIO docs. Is this possible?
I'm using the semaphore to fix the handlers queue size. The following code illustrate this solution:
void Schedule(boost::function<void()> function)
{
semaphore.wait();
io_service.post(boost::bind(&TaskWrapper, function));
}
void TaskWrapper(boost::function<void()> &function)
{
function();
semaphore.post();
}
You can wrap your lambda in another lambda which would take care of counting the "in-progress" tasks, and then wait before posting if there are too many in-progress tasks.
Example:
#include <atomic>
#include <chrono>
#include <future>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <boost/asio.hpp>
class ThreadPool {
using asio_worker = std::unique_ptr<boost::asio::io_service::work>;
boost::asio::io_service service;
asio_worker service_worker;
std::vector<std::thread> grp;
std::atomic<int> inProgress = 0;
std::mutex mtx;
std::condition_variable busy;
public:
ThreadPool(int threads) : service(), service_worker(new asio_worker::element_type(service)) {
for (int i = 0; i < threads; ++i) {
grp.emplace_back([this] { service.run(); });
}
}
template<typename F>
void enqueue(F && f) {
std::unique_lock<std::mutex> lock(mtx);
// limit queue depth = number of threads
while (inProgress >= grp.size()) {
busy.wait(lock);
}
inProgress++;
service.post([this, f = std::forward<F>(f)]{
try {
f();
}
catch (...) {
inProgress--;
busy.notify_one();
throw;
}
inProgress--;
busy.notify_one();
});
}
~ThreadPool() {
service_worker.reset();
for (auto& t : grp)
if (t.joinable())
t.join();
service.stop();
}
};
int main() {
std::unique_ptr<ThreadPool> pool(new ThreadPool(4));
for (int i = 1; i <= 20; ++i) {
pool->enqueue([i] {
std::string s("Hello from task ");
s += std::to_string(i) + "\n";
std::cout << s;
std::this_thread::sleep_for(std::chrono::seconds(1));
});
}
std::cout << "All tasks queued.\n";
pool.reset(); // wait for all tasks to complete
std::cout << "Done.\n";
}
Output:
Hello from task 3
Hello from task 4
Hello from task 2
Hello from task 1
Hello from task 5
Hello from task 7
Hello from task 6
Hello from task 8
Hello from task 9
Hello from task 10
Hello from task 11
Hello from task 12
Hello from task 13
Hello from task 14
Hello from task 15
Hello from task 16
Hello from task 17
Hello from task 18
All tasks queued.
Hello from task 19
Hello from task 20
Done.
you could use the strand object to put the events and put a delay in your main ? Is your program dropping out after all the work is posted? If so you can use the work object which will give you more control over when your io_service stops.
you could always main check the state of the threads and have it wait untill one becomes free or something like that.
//links
http://www.boost.org/doc/libs/1_40_0/doc/html/boost_asio/reference/io_service__strand.html
http://www.boost.org/doc/libs/1_40_0/doc/html/boost_asio/reference/io_service.html
//example from the second link
boost::asio::io_service io_service;
boost::asio::io_service::work work(io_service);
hope this helps.
Maybe try lowering the priority of the main thread so that once the worker threads get busy they starve the main thread and the system self limits.