I have a requirement of executing a callback function on exit of a std::thread and the callback function should be executed on the main thread.
On thread creation I need to detach the thread and cannot block the main loop execution for thread completion.
i tried using std::signal but that does not seem to execute callback function on the main thread
#include <thread>
#include <csignal>
#include <iostream>
std::thread::id main_thread_id;
void func2()
{
for(int i = 0; i < 10000000; i++)
{
// do something
}
}
void func()
{
for(int i = 0; i < 10; i++)
{
func2();
}
std::raise(SIGUSR1);
}
void callback(int signal)
{
std::cout << "SIGNAL: " << signal << " THREAD ID:" <<
std::this_thread::get_id() << std::endl;
bool b = std::this_thread::get_id() == main_thread_id;
std::cout << "IS EXECUTED ON MAIN THREAD: " << b << std::endl;
}
int main()
{
main_thread_id = std::this_thread::get_id();
std::cout << "MAIN THREAD ID: " << std::this_thread::get_id() << std::endl;
std::signal(SIGUSR1, callback);
std::thread t1(func);
t1.detach();
for(int i = 0; i < 20; i++)
{
func2();
}
if(t1.joinable())
t1.join();
}
The result I get is that the callback function is not executed on main thread. Please suggest a way in which I can create a worker thread and call a callback function on main thread upon exit of the thread.
Thanks for the help
There are a few ways to do this.
First, your main thread could be running a message loop. In which case, you queue up a message with a payload that tells the main thread to run some code (either carry the code to run via a pointer part of the message to the main thread, or put it in some known spot that the main thread checks).
A second approach is to return something like a std::future<std::function<void()>> object, and the main thread checks if the future is ready. When it is ready, it runs the code.
A third approach is to create a concurrent queue that the main thread waits on, and stuff your message (containing code to run) onto that queue.
All of these things require the active cooperation of the main thread. The main thread cannot be preemted and told to run different code without its cooperation.
Which is best depends on features of your program you did not choose to mention in your question. If you are a graphical GUI with a message loop, use the message loop. If you are a streaming processor that paralellizes some work, and you don't need prompt execution, yet eventually will want to block on the parallel work, a future might be best. If you are a message passing channel-type app, a set of queues might be best.
Related
I'm studying concurrency in C++ and I'm trying to implement a multithreaded callback registration system. I came up with the following code, which is supposed to accept registration requests until an event occurs. After that, it should execute all the registered callbacks in order with which they were registered. The registration order doesn't have to be deterministic.
The code doesn't work as expected. First of all, it rarely prints the "Pushing callback with id" message. Secondly, it sometimes hangs (a deadlock caused by a race condition, I assume). I'd appreciate help in figuring out what's going on here. If you see that I overcomplicate some parts of the code or misuse some pieces, please also point it out.
#include <condition_variable>
#include <functional>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
class CallbackRegistrar{
public:
void registerCallbackAndExecute(std::function<void()> callback) {
if (!eventTriggered) {
std::unique_lock<std::mutex> lock(callbackMutex);
auto saved_id = callback_id;
std::cout << "Pushing callback with id " << saved_id << std::endl;
registeredCallbacks.push(std::make_pair(callback_id, callback));
++callback_id;
callbackCond.wait(lock, [this, saved_id]{return releasedCallback.first == saved_id;});
releasedCallback.second();
callbackExecuted = true;
eventCond.notify_one();
}
else {
callback();
}
}
void registerEvent() {
eventTriggered = true;
while (!registeredCallbacks.empty()) {
releasedCallback = registeredCallbacks.front();
callbackCond.notify_all();
std::unique_lock<std::mutex> lock(eventMutex);
eventCond.wait(lock, [this]{return callbackExecuted;});
callbackExecuted = false;
registeredCallbacks.pop();
}
}
private:
std::queue<std::pair<unsigned, std::function<void()>>> registeredCallbacks;
bool eventTriggered{false};
bool callbackExecuted{false};
std::mutex callbackMutex;
std::mutex eventMutex;
std::condition_variable callbackCond;
std::condition_variable eventCond;
unsigned callback_id{1};
std::pair<unsigned, std::function<void()>> releasedCallback;
};
int main()
{
CallbackRegistrar registrar;
std::thread t1(&CallbackRegistrar::registerCallbackAndExecute, std::ref(registrar), []{std::cout << "First!\n";});
std::thread t2(&CallbackRegistrar::registerCallbackAndExecute, std::ref(registrar), []{std::cout << "Second!\n";});
registrar.registerEvent();
t1.join();
t2.join();
return 0;
}
This answer has been edited in response to more information being provided by the OP in a comment, the edit is at the bottom of the answer.
Along with the excellent suggestions in the comments, the main problem that I have found in your code is with the callbackCond condition variable wait condition that you have set up. What happens if releasedCallback.first does not equal savedId?
When I have run your code (with a thread-safe queue and eventTriggered as an atomic) I found that the problem was in this wait function, if you put a print statement in that function you will find that you get something like this:
releasedCallback.first: 0, savedId: 1
This then waits forever.
In fact, I've found that the condition variables used in your code aren't actually needed. You only need one, and it can live inside the thread-safe queue that you are going to build after some searching ;)
After you have the thread-safe queue, the code from above can be reduced to:
class CallbackRegistrar{
public:
using NumberedCallback = std::pair<unsigned int, std::function<void()>>;
void postCallback(std::function<void()> callback) {
if (!eventTriggered)
{
std::unique_lock<std::mutex> lock(mutex);
auto saved_id = callback_id;
std::cout << "Pushing callback with id " << saved_id << std::endl;
registeredCallbacks.push(std::make_pair(callback_id, callback));
++callback_id;
}
else
{
while (!registeredCallbacks.empty())
{
NumberedCallback releasedCallback;
registeredCallbacks.waitAndPop(releasedCallback);
releasedCallback.second();
}
callback();
}
}
void registerEvent() {
eventTriggered = true;
}
private:
ThreadSafeQueue<NumberedCallback> registeredCallbacks;
std::atomic<bool> eventTriggered{false};
std::mutex mutex;
unsigned int callback_id{1};
};
int main()
{
CallbackRegistrar registrar;
std::vector<std::thread> threads;
for (int i = 0; i < 10; i++)
{
threads.push_back(std::thread(&CallbackRegistrar::postCallback,
std::ref(registrar),
[i]{std::cout << std::to_string(i) <<"\n";}
));
}
registrar.registerEvent();
for (auto& thread : threads)
{
thread.join();
}
return 0;
}
I'm not sure if this does exactly what you want, but it doesn't deadlock. It's a good starting point in any case, but you need to bring your own implementation of ThreadSafeQueue.
Edit
This edit is in response to the comment by the OP stating that "once the event occurs, all the callbacks should be executed in [the] order that they've been pushed to the queue and by the same thread that registered them".
This was not mentioned in the original question post. However, if that is the required behaviour then we need to have a condition variable wait in the postCallback method. I think this is also the reason why the OP had the condition variable in the postCallback method in the first place.
In the code below I have made a few edits to the callbacks, they now take input parameters. I did this to print some useful information while the code is running so that it is easier to see how it works, and, importantly how the condition variable wait is working.
The basic idea is similar to what you had done, I've just trimmed out the stuff you didn't need.
class CallbackRegistrar{
public:
using NumberedCallback = std::pair<unsigned int, std::function<void(int, int)>>;
void postCallback(std::function<void(int, int)> callback, int threadId) {
if (!m_eventTriggered)
{
// Lock the m_mutex
std::unique_lock<std::mutex> lock(m_mutex);
// Save the current callback ID and push the callback to the queue
auto savedId = m_currentCallbackId++;
std::cout << "Pushing callback with ID " << savedId << "\n";
m_registeredCallbacks.push(std::make_pair(savedId, callback));
// Wait until our thread's callback is next in the queue,
// this will occur when the ID of the last called callback is one less than our saved callback.
m_conditionVariable.wait(lock, [this, savedId, threadId] () -> bool
{
std::cout << "Waiting on thread " << threadId << " last: " << m_lastCalledCallbackId << ", saved - 1: " << (savedId - 1) << "\n";
return (m_lastCalledCallbackId == (savedId - 1));
});
// Once we are finished waiting, get the callback out of the queue
NumberedCallback retrievedCallback;
m_registeredCallbacks.waitAndPop(retrievedCallback);
// Update last callback ID and call the callback
m_lastCalledCallbackId = retrievedCallback.first;
retrievedCallback.second(m_lastCalledCallbackId, threadId);
// Notify one waiting thread
m_conditionVariable.notify_one();
}
else
{
// If the event is already triggered, call the callback straight away
callback(-1, threadId);
}
}
void registerEvent() {
// This is all we have to do here.
m_eventTriggered = true;
}
private:
ThreadSafeQueue<NumberedCallback> m_registeredCallbacks;
std::atomic<bool> m_eventTriggered{ false};
std::mutex m_mutex;
std::condition_variable m_conditionVariable;
unsigned int m_currentCallbackId{ 1};
std::atomic<unsigned int> m_lastCalledCallbackId{ 0};
};
The main function is as above, except I am creating 100 threads instead of 10, and I have made the callback print out information about how it was called.
for (int createdThreadId = 0; createdThreadId < 100; createdThreadId++)
{
threads.push_back(std::thread(&CallbackRegistrar::postCallback,
std::ref(registrar),
[createdThreadId](int registeredCallbackId, int callingThreadId)
{
if (registeredCallbackId < 0)
{
std::cout << "Callback " << createdThreadId;
std::cout << " called immediately, from thread: " << callingThreadId << "\n";
}
else
{
std::cout << "Callback " << createdThreadId;
std::cout << " called from thread " << callingThreadId;
std::cout << " after being registered as " << registeredCallbackId << "\n";
}
},
createdThreadId));
}
I am not entirely sure why you want to do this, as it seems to defeat the point of having multiple threads, although I may be missing something there. But, regardless, I hope this helps you to understand better the problem you are trying to solve.
Experimenting with this code some more, I found out why the "Pushing callback with id " part was rarely printed. It's because the call to registrar.registerEvent from the main thread was usually faster than the calls to registerCallbackAndExecute from separate threads. Because of that, the condition if (!eventTriggered) was almost never fulfilled (eventTriggered had been set to true in the registerEvent method) and hence all calls to registerCallbackAndExecute were falling into the else branch and executing straightaway.
Then, the program sometimes also didn't finish, because of a race condition between registerEvent and registerCallbackAndExecute. Sometimes, registerEvent was being called after the check if (!eventTriggered) but before pushing the callback to the queue. Then, registerEvent completed instantly (as the queue was empty) while the thread calling registerCallbackAndExecute was pushing the callback to the queue. The latter thread then kept waiting forever for the event (that had already happened) to happen.
i just ask my self:when i make pool of threads in code
then i compile the code ,
does the compiled code have a copy for each thread?
and if i use macro function , and pass it to the threads,
is this macro expanded during compile time"what i think" or during runtime,
and if it is in compile time why this following code need mutex:
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
#include <iostream>
namespace asio = boost::asio;
#define PRINT_ARGS(msg) do {\
boost::lock_guard<boost::mutex> lg(mtx); \
std::cout << '[' << boost::this_thread::get_id() \
<< "] " << msg << std::endl; \
} while (0)
int main() {
asio::io_service service;
boost::mutex mtx;
for (int i = 0; i < 20; ++i) {
service.post([i, &mtx]() {
PRINT_ARGS("Handler[" << i << "]");
boost::this_thread::sleep(
boost::posix_time::seconds(1));
});
}
boost::thread_group pool;
for (int i = 0; i < 4; ++i) {
pool.create_thread([&service]() { service.run(); });
}
pool.join_all();
}
here the lock_guard make cout critical section,although only the main thread will be the thread posting to io_service
then the threads running tasks will work on already made queue of already made lamda functions >>>>which make me think there is no need for mutex?
is this thinking right?
here i will simulate the macro expansion during compilation:
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
#include <iostream>
namespace asio = boost::asio;
#define PRINT_ARGS(msg) do {\
boost::lock_guard<boost::mutex> lg(mtx); \
std::cout << '[' << boost::this_thread::get_id() \
<< "] " << msg << std::endl; \
} while (0)
int main() {
asio::io_service service;
boost::mutex mtx;
for (int i = 0; i < 20; ++i) {
service.post([i, &mtx]() {
//PRINT_ARGS("Handler[" << i << "]");//>>>>>this will be
do {\\
boost::lock_guard<boost::mutex> lg(mtx); \\
std::cout << '[' << boost::this_thread::get_id() \\
<< "] " << "Handler[" << i << "]" << std::endl; \\
} while (0)
boost::this_thread::sleep(
boost::posix_time::seconds(1));
});
}
boost::thread_group pool;
for (int i = 0; i < 4; ++i) {
pool.create_thread([&service]() { service.run(); });
}
pool.join_all();
}
and then the program will be in the following order:
1- main thread :make io_service instance
2- main thread :make mutex instance
3- main thread :make for loop 20 times ,each time the main thread post a task"the lambda function" which is defined in the book having this code as adding this function object to an internal queue in io_service so
my question is :does the main thread add 20 lambda function objects to the queue and in this case each one would have certain value of i
and then when the new 4 threads start work,he gives them thread function "run" which according to same book remove the function objects one by one and execute them one by one
in this case:
thread 1:removes lambda 1 and execute it with its own code as being separate instance with unique i
thread 2:removes lambda 2 and execute it with its own code as being separate instance with unique i
thread 3:removes lambda 3 and execute it with its own code as being separate instance with unique i
thread 4:removes lambda 4 and execute it with its own code as being separate instance with unique i
then thread one againget lambda 5
this is based on my understanding that the queue has 20 function objects as lambda functions"may be wrapped in somesort of wrapper" and thus each thread will take separate object and for this reason need no mutex"20 internal assembly codes after compilation"
but if the tasks in queue are just references to the same single code"but when it execute the for loop" ,then it will need mutex to prevent 2 threads accessing the critical code at same time
which scenario is the present here by code signs?
Macros are always expanded at compile time but the compiler has only very rudimentary knowledge of threads (mostly regarding being able to say that certain variables are thread local).
Code is only going to exist once in either the on-disk image or in-memory copy that actually gets run.
Locking the mutex in PRINT_ARGS ensures that each operation's message is printed in its entirety without getting interrupted by another thread. (Otherwise you might have a operation start to print its message, get interrupted by another operation on a different thread which does print its message and then the remainder of the first operation's message gets printed).
I was learning boost asio documentation.I came across this deadline_timer example.
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
/*This timer example shows a timer that fires once every second.*/
void print(const boost::system::error_code& e, boost::asio::deadline_timer* t, int* count)
{
if (*count < 5)
{
std::cout << *count << std::endl;
++(*count);
t->expires_at(t->expires_at() + boost::posix_time::seconds(1));
t->async_wait(boost::bind(print,boost::asio::placeholders::error, t, count));
}
}
int main()
{
boost::asio::io_service io;
int count = 0;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(10));
auto myfunc = boost::bind(print, boost::asio::placeholders::error, &t ,&count);
t.async_wait(myfunc);
std::cout << "async wait " << std::endl;
io.run();
std::cout << "Just called io.run() " << std::endl;
std::cout << "Final count is " << count << std::endl;
return 0;
}
The async_wait() function seems to be blocking (i.e waiting for the 10 second timer to expire)
The output from the above program is as follows.
async wait
0
1
2
3
4
Just called io.run()
Final count is 5
I would expect an async_wait() to create a separate thread and wait for the timer to expire there meanwhile executing the main thread.
i.e I would expect the program to print
Just called io.run()
Final count is 5
while waiting for the timer to expire.? Is my understanding wrong?
This is my understanding of async_wait(). This implementation looks more like a blocking wait. Is my understanding wrong? What am I missing?
The io.run(); statement is the key to explaining the difference between the output you're getting and the output you're expecting.
In the ASIO framework, any asynchronous commands need to have a dedicated thread to run the callbacks upon. But because ASIO is relatively low-level, it expects you to provide the thread yourself.
As a result, what you're doing when you call io.run(); within the main thread is to specify to the framework that you intend to run all asynchronous commands on the main thread. That's acceptable, but that also means that the program will block on io.run();.
If you intend the commands to run on a separate thread, you'll have to write something like this:
std::thread run_thread([&]() {
io.run();
});
std::cout << "Just called io.run() " << std::endl;
std::cout << "Final count is " << count << std::endl;
run_thread.join();
return 0;
The async_wait function isn't blocking, run is. That's run's job. If you don't want a thread to block in the io_service's processing loop, don't have that thread call run.
The async_wait function doesn't create any threads. That would make it expensive and make it much harder to control the number of threads servicing the io_service.
Your expectation is unreasonable because returning from main terminates the process. So who or what would wait for the timer?
I am beginning to use the thread class.
In the main() thread below, an Example class is created.
Inside the constructor of Example, two threads are created in the Example::start() function.
Example::foo() is designed to print a message every second.
Example::bar() is designed to print a message every 5 seconds.
Inside the main() function, a loop is designed to print every 3 seconds.
I decided to not use join() in Example::start() because I would like to have the main() function continuously run.
Why does the main thread crash during run-time?
// thread example
#include <iostream> // std::cout
#include <thread> // std::thread
#include <chrono> // std::chrono::seconds
using namespace std;
class Example
{
public:
Example();
void start();
void foo();
void bar(int x);
};
Example::Example()
{
start();
}
void Example::start()
{
std::thread first (&Example::foo, this); // spawn new thread that calls foo()
std::thread second (&Example::bar, this, 5); // spawn new thread that calls bar(0)
// synchronize threads:
//first.join(); // pauses until first finishes
//second.join(); // pauses until second finishes
}
void Example::foo()
{
cout << "entered foo()" << endl;
int count = 0;
while(1) {
std::this_thread::sleep_for (std::chrono::seconds(1));
++count;
cout << "foo() count = " << count << endl;
}
}
void Example::bar(int x)
{
cout << "entered bar() x = " << x << endl;
int count = 0;
while(1) {
std::this_thread::sleep_for (std::chrono::seconds(5));
++count;
cout << "bar() count = " << count << endl;
}
}
int main() {
Example* c = new Example();
cout << "Example() created" << endl;
while(true) {
std::this_thread::sleep_for(std::chrono::seconds(3));
cout << "main() thread loop..." << endl;
}
std::cout << "end of main()";
delete c;
return 0;
}
Foo::Start() initalizes two threads, thread Foo and thread bar. When the function Start returns to the main thread, the two thread objects go out of scope and the destructor is called for clearing out of scope variables.
A simple solution would be to make threads part of the class.
On another note, std::cout is not a synchronized class, when writing your text might be garbled: Is cout synchronized/thread-safe?
Also, when creating your class Example, delete is never called which causes a memory leak.
Your comment here:
void Example::start()
{
std::thread first (&Example::foo, this); // spawn new thread that calls foo()
std::thread second (&Example::bar, this, 5); // spawn new thread that calls bar(0)
// synchronize threads:
//first.join(); // pauses until first finishes
//second.join(); // pauses until second finishes
}
Is wrong.
Not only does the the join pause until the threads finish. But they also allow the thread to be cleaned up. A thread destructor calls terminate while the thread is join-able (ie it is still running). So you must call join() on the thread (to wait for it to finish) before you can allow the destructor to be called.
One of the comments above suggests calling detach(). This detaches the thread of execution from the thread object (thus making it not join-able). This will work (as your code is in infinite loop), but is a bad idea generally. As allowing main() to exit while threads are still running is undefined behavior.
In Java, I would do something like:
Thread t = new MyThread();
t.start();
I start thread by calling start() method. So later I can do something like:
for (int i = 0; i < limit; ++i)
{
Thread t = new MyThread();
t.start();
}
To create a group of threads and execute the code in run() method.
However, in C++, there's no such thing as start() method. Using Boost, if I want a thread to start running, I have to call the join() method in order to make a thread running.
#include <iostream>
#include <boost/thread.hpp>
class Worker
{
public:
Worker()
{
// the thread is not-a-thread until we call start()
}
void start(int N)
{
m_Thread = boost::thread(&Worker::processQueue, this, N);
}
void join()
{
m_Thread.join();
}
void processQueue(unsigned N)
{
float ms = N * 1e3;
boost::posix_time::milliseconds workTime(ms);
std::cout << "Worker: started, will work for "
<< ms << "ms"
<< std::endl;
// We're busy, honest!
boost::this_thread::sleep(workTime);
std::cout << "Worker: completed" << std::endl;
}
private:
boost::thread m_Thread;
};
int main(int argc, char* argv[])
{
std::cout << "main: startup" << std::endl;
Worker worker, w2, w3, w5;
worker.start(3);
w2.start(3);
w3.start(3);
w5.start(3);
worker.join();
w2.join();
w3.join();
w5.join();
for (int i = 0; i < 100; ++i)
{
Worker w;
w.start(3);
w.join();
}
//std::cout << "main: waiting for thread" << std::endl;
std::cout << "main: done" << std::endl;
return 0;
}
On the code above, the for loop to create 100 threads, normally I must use a boost::thread_group to add the thread function, and finally run all with join_all(). However, I don't know how to do it with thread function putting in a class which uses various class members.
On the other hand, the loop above will not behave like the loop in Java. It will make each thread execute sequentially, not all at once like the other separated threads, whose own join() is called.
What is join() in Boost exactly? Also please help me to create a group of threads which share the same class.
join doesn't start the thread, it blocks you until the thread you're joining finishes. You use it when you need to wait for the thread you started to finish its run (for example - if it computes something and you need the result).
What starts the thread is boost::thread, which creates the thread and calls the thread function you passed to it (in your case - Worker::processQueue).
The reason you had a problem with the loop is not because the threads didn't start, but because your main thread didn't wait for them to execute before finishing. I'm guessing you didn't see this problem in Java because of the scheduling differences, aka "undefined behavior". after edit In Java the threading behaves slightly differently, see the comment below for details. That explains why you didn't see it in Java.
Here's a question about the boost::thread_group. Read the code in the question and the answers, it will help you.
Joining a thread does the same thing in Boost as it does in Java: it waits for the thread to finish running.
Plus, if I remember correctly, Boost's threads run upon construction. You don't start them explicitly.