How to send signal/data from a worker thread to main thread? - multithreading

I'll preface this by saying that I'm delving into multithreading for the first time. Despite a lot of reading on concurrency and synchronization, I'm not readily seeing a solution for the requirements I've been given.
Using C++11 and Boost, I'm trying to figure out how to send data from a worker thread to a main thread. The worker thread is spawned at the start of the application and continuously monitors a lock free queue. Objects populate this queue at various intervals. This part is working.
Once the data is available, it needs to be processed by the main thread since another signal will be sent to the rest of the application which cannot be on a worker thread. This is what I'm having trouble with.
If I have to block the main thread through a mutex or a condition variable until the worker thread is done, how will that improve responsiveness? I might as well just stay with a single thread so I have access to the data. I must be missing something here.
I have posted a couple questions, thinking that Boost::Asio was the way to go. There is an example of how signals and data can be sent between threads, but as the responses indicate, things get quickly overly-complicated and it's not working perfectly:
How to connect signal to boost::asio::io_service when posting work on different thread?
Boost::Asio with Main/Workers threads - Can I start event loop before posting work?
After speaking with some colleagues, it was suggested that two queues be used -- one input, one output. This would be in shared space and the output queue would be populated by the worker thread. The worker thread is always going but there would need to be a Timer, probably at the application level, that would force the main thread to examine the output queue to see if there were any pending tasks.
Any ideas on where I should direct my attention? Are there any techniques or strategies that might work for what I'm trying to do? I'll be looking at Timers next.
Thanks.
Edit: This is production code for a plugin system that post-processes simulation results. We are using C++11 first wherever possible, followed by Boost. We are using Boost's lockfree::queue. The application is doing what we want on a single thread but now we are trying to optimize where we see that there are performance issues (in this case, a calculation happening through another library). The main thread has a lot of responsibilities, including database access, which is why I want to limit what the worker thread actually does.
Update: I have already been successful in using std::thread to launch a worker thread that examines a Boost lock::free queue and processes tasks placed it in. It's step 5 in #Pressacco's response that I'm having trouble with. Any examples returning a value to the main thread when a worker thread is finished and informing the main thread, rather than simply waiting for the worker to finish?

If your objective is develop the solution from scratch (using native threads, queues, etc.):
create a thread save queue queue (Mutex/CriticalSection around add/remove)
create a counting semaphore that is associated with the queue
have one or more worker threads wait on the counting semaphore (i.e. the thread will block)
the semaphore is more efficient than having the thread constantly poll the queue
as messages/jobs are added to the queue, increment the semaphore
a thread will wake up
the thread should remove one message
if a result needs to be returned...
setup another: Queue+Semaphore+WorkerThreads
ADDITIONAL NOTES
If you decide to implement a thread safe queue from scratch, take a look at:
Synchronization between threads using Critical Section
With that said, I would take another look at BOOST. I haven't used the library, but from what I hear it will most likely contain some relevant data structures (e.g. a thread safe queue).
My favorite quote from the MSDN:
"When you use multithreading of any sort, you potentially expose
yourself to very serious and complex bugs"
SIDEBAR
Since you are looking at concurrent programming for the first time, you may wish to consider:
Is your objective to build production worthy code , or is this simply a learning exercise?
production? consider us existing proven libraries
learning? consider writing the code from scratch
Consider using a thread pool with an asynchronous callback instead of native threads.
more threads != better
Are threads really needed?
Follow the KISS principle.

The feedback above led me in the right direction for what I needed. The solution was definitely simpler than having to use signals/slots or Boost::Asio as I had previously attempted. I have two lock-free queues, one for input (on a worker thread) and one for output (on the main thread, populated by the worker thread). I use a timer to schedule when the output queue is processed. The code is below; perhaps it is of use to somebody:
//Task.h
#include <iostream>
#include <thread>
class Task
{
public:
Task(bool shutdown = false) : _shutdown(shutdown) {};
virtual ~Task() {};
bool IsShutdownRequest() { return _shutdown; }
virtual int Execute() = 0;
private:
bool _shutdown;
};
class ShutdownTask : public Task
{
public:
ShutdownTask() : Task(true) {}
virtual int Execute() { return -1; }
};
class TimeSeriesTask : public Task
{
public:
TimeSeriesTask(int value) : _value(value) {};
virtual int Execute()
{
std::cout << "Calculating on thread " << std::this_thread::get_id() << std::endl;
return _value * 2;
}
private:
int _value;
};
// Main.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include "afxwin.h"
#include <boost/lockfree/spsc_queue.hpp>
#include "Task.h"
static UINT_PTR ProcessDataCheckTimerID = 0;
static const int ProcessDataCheckPeriodInMilliseconds = 100;
class Manager
{
public:
Manager()
{
//Worker Thread with application lifetime that processes a lock free queue
_workerThread = std::thread(&Manager::ProcessInputData, this);
};
virtual ~Manager()
{
_workerThread.join();
};
void QueueData(int x)
{
if (x > 0)
{
_inputQueue.push(std::make_shared<TimeSeriesTask>(x));
}
else
{
_inputQueue.push(std::make_shared<ShutdownTask>());
}
}
void ProcessOutputData()
{
//process output data on the Main Thread
_outputQueue.consume_one([&](int value)
{
if (value < 0)
{
PostQuitMessage(WM_QUIT);
}
else
{
int result = value - 1;
std::cout << "Final result is " << result << " on thread " << std::this_thread::get_id() << std::endl;
}
});
}
private:
void ProcessInputData()
{
bool shutdown = false;
//Worker Thread processes input data indefinitely
do
{
_inputQueue.consume_one([&](std::shared_ptr<Task> task)
{
std::cout << "Getting element from input queue on thread " << std::this_thread::get_id() << std::endl;
if (task->IsShutdownRequest()) { shutdown = true; }
int result = task->Execute();
_outputQueue.push(result);
});
} while (shutdown == false);
}
std::thread _workerThread;
boost::lockfree::spsc_queue<std::shared_ptr<Task>, boost::lockfree::capacity<1024>> _inputQueue;
boost::lockfree::spsc_queue<int, boost::lockfree::capacity<1024>> _outputQueue;
};
std::shared_ptr<Manager> g_pMgr;
//timer to force Main Thread to process Manager's output queue
void CALLBACK TimerCallback(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
if (nIDEvent == ProcessDataCheckTimerID)
{
KillTimer(NULL, ProcessDataCheckPeriodInMilliseconds);
ProcessDataCheckTimerID = 0;
//call function to process data
g_pMgr->ProcessOutputData();
//reset timer
ProcessDataCheckTimerID = SetTimer(NULL, ProcessDataCheckTimerID, ProcessDataCheckPeriodInMilliseconds, (TIMERPROC)&TimerCallback);
}
}
int main()
{
std::cout << "Main thread is " << std::this_thread::get_id() << std::endl;
g_pMgr = std::make_shared<Manager>();
ProcessDataCheckTimerID = SetTimer(NULL, ProcessDataCheckTimerID, ProcessDataCheckPeriodInMilliseconds, (TIMERPROC)&TimerCallback);
//queue up some dummy data
for (int i = 1; i <= 10; i++)
{
g_pMgr->QueueData(i);
}
//queue a shutdown request
g_pMgr->QueueData(-1);
//fake the application's message loop
MSG msg;
bool shutdown = false;
while (shutdown == false)
{
if (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
shutdown = true;
}
}
return 0;
}

Related

Does a condition variable really need another variable?

Note: I'll give examples in C++ but I believe my question is language-agnostic. Correct me if I'm wrong.
Just so you really understand me - what I'm trying to learn here is what the tool does and nothing else. Not what it's usually used for, not what the conventions says, just what the blunt tool does. In this case - what the condition variable does.
So far it seems to me like it's a simple mechanism that allows threads to wait (block) until some other thread signals them (unblocks them). Nothing more, no dealing with critical section access or data access (of course they can be used for that but it's only a matter of programmer's choice). Also the signaling is usually only done when something important happens (e.g. data was loaded) but theoretically it could be called at any time. Correct so far?
Now, every example that I have seen uses a condition variable object (e.g. std::condition_variable) but also some additional variable to mark if something happened (e.g. bool dataWasLoaded). Take a look at this example from https://thispointer.com//c11-multithreading-part-7-condition-variables-explained/:
#include <iostream>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
using namespace std::placeholders;
class Application
{
std::mutex m_mutex;
std::condition_variable m_condVar;
bool m_bDataLoaded;
public:
Application()
{
m_bDataLoaded = false;
}
void loadData()
{
// Make This Thread sleep for 1 Second
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "Loading Data from XML" << std::endl;
// Lock The Data structure
std::lock_guard<std::mutex> guard(m_mutex);
// Set the flag to true, means data is loaded
m_bDataLoaded = true;
// Notify the condition variable
m_condVar.notify_one();
}
bool isDataLoaded()
{
return m_bDataLoaded;
}
void mainTask()
{
std::cout << "Do Some Handshaking" << std::endl;
// Acquire the lock
std::unique_lock<std::mutex> mlock(m_mutex);
// Start waiting for the Condition Variable to get signaled
// Wait() will internally release the lock and make the thread to block
// As soon as condition variable get signaled, resume the thread and
// again acquire the lock. Then check if condition is met or not
// If condition is met then continue else again go in wait.
m_condVar.wait(mlock, std::bind(&Application::isDataLoaded, this));
std::cout << "Do Processing On loaded Data" << std::endl;
}
};
int main()
{
Application app;
std::thread thread_1(&Application::mainTask, &app);
std::thread thread_2(&Application::loadData, &app);
thread_2.join();
thread_1.join();
return 0;
}
Now, other than the std::condition_variable m_condVar it also uses an additional variable bool m_bDataLoaded. But it seems to me that the thread performing mainTask is already notified that the data was loaded by means of std::condition_variable m_condVar. Why also check bool m_bDataLoaded for the same information? Compare (the same code without bool m_bDataLoaded):
#include <iostream>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
using namespace std::placeholders;
class Application
{
std::mutex m_mutex;
std::condition_variable m_condVar;
public:
Application()
{
}
void loadData()
{
// Make This Thread sleep for 1 Second
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "Loading Data from XML" << std::endl;
// Lock The Data structure
std::lock_guard<std::mutex> guard(m_mutex);
// Notify the condition variable
m_condVar.notify_one();
}
void mainTask()
{
std::cout << "Do Some Handshaking" << std::endl;
// Acquire the lock
std::unique_lock<std::mutex> mlock(m_mutex);
// Start waiting for the Condition Variable to get signaled
// Wait() will internally release the lock and make the thread to block
// As soon as condition variable get signaled, resume the thread and
// again acquire the lock. Then check if condition is met or not
// If condition is met then continue else again go in wait.
m_condVar.wait(mlock);
std::cout << "Do Processing On loaded Data" << std::endl;
}
};
int main()
{
Application app;
std::thread thread_1(&Application::mainTask, &app);
std::thread thread_2(&Application::loadData, &app);
thread_2.join();
thread_1.join();
return 0;
}
Now I know about spurious wakeups and they alone necessitate the usage of an additional variable. My question is - are they they only reason for it? If they didn't occur could one just use condition variables without any additional variables (and btw wouldn't that make the name "condition variable" a misnomer then)?
Another thing is - isn't the usage of additional variables the only reason why condition variables also require a mutex? If not, what are the other reasons?
If additional variables are necessary (for spurious wakeups or other reasons) why doesn't the API require them (in the 2nd code I didn't have to use them for the code to compile)? (I don't know if it's the same in other languages, so this question might be C++-specific.)
It's not all about spurious wakeups.
When you call m_condvar.wait, how do you know the condition you're waiting for has not already happened?
Maybe 'loadData' has already been called in another thread. When it called notify_one(), nothing happened because there were no threads waiting.
Now if you call condvar.wait, you will wait forever because nothing will signal you.
The original version does not have this problem, because:
If m_bDataLoaded is false, then it knows that the data is not loaded, and that after m_bDataLoaded is set true, the caller will signal the condition;
The lock is held, and we know that m_bDataLoaded cannot be modified in another thread until it's released;
condvar.wait will put the current thread in the waiting queue before releasing the lock, so we know that m_bDataLoaded will be set true after we start waiting, and so notify_one will also be called after we start waiting.
To answer your other questions:
Yes, coordination with additional variables is the reason why condition variables are tied to mutexes.
The API doesn't require, say, a boolean variable, because that's not always the kind of condition you're waiting for.
This kind of thing is common, for example:
Task *getTask() {
//anyone who uses m_taskQueue or m_shutDown must lock this mutex
unique_lock<mutex> lock(m_mutex);
while (m_taskQueue.isEmpty()) {
if (m_shutdown) {
return null;
}
// this is signalled after a task is enqueued
// or m_shutdown is asserted
m_condvar.wait(lock);
}
return taskQueue.pop_front();
}
Here we require the same critical guarantee that the thread starts waiting before the lock is released, but the condition we're waiting for is more complex, involving a variable and separate data structure, and there are multiple ways to exit the wait.
Yes, the condition variable is just useful to wait for an event. In my point of view you should not try to use it for controlling concurrent access of critical data structures.
I just can speak about C++. As you see in the example here https://en.cppreference.com/w/cpp/thread/condition_variable/wait, they used this expression cv.wait(lk, []{return i == 1;});. And []{...} is the expression of a nameless function. So you can also write your own function and give the name of the function:
bool condFn()
{
std::cout << "condFn" << std::endl; // debug output ;)
return i == 1;
}
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cerr << "Waiting... \n";
cv.wait(lk, condFn);
std::cerr << "...finished waiting. i == 1\n";
}
And inside this function you can evaluate, whatever you want. The thread is always sleeping until it gets notified, then it processes always the function that evaluates the condition for continue working. In case of true, the thread continues, in case of false the programm goes sleeping again.

Get result of future without blocking

This question has been asked before and if I am not wrong, the only way to read the result of a future is either to call get() and block until it is ready or using wait_for() with zero duration as mentioned in the answer - Get the status of a std::future
But, if I just want a worker thread to return me a result that I want it to compute and not wait or block myself for it to complete, can I not just pass it a callback that the worker thread can call when it has computed the result for me? Something like below -
#include <iostream>
#include <thread>
#include <functional>
void foo(std::function<void(int)> callback)
{
int result = 5;
callback(result);
}
int main()
{
int result = 0;
std::thread worker(foo, [](int result)
{
std::cout << "Result from worker is " << result << std::endl;
});
worker.join();
}
Here, the worker thread would just execute the callback when it has computed the result for me. I don't have to wait for it to finish or block or check in a loop to know when it's ready.
Please advice is this is a good approach to be used as currently there is no way to do this without blocking or checking for it in a loop?
You can certainly create your own thread with a callback, but as soon as you move away from a toy example you will notice that you have potentially created a synchronization problem. This is because your callback is being invoked from a separate thread. So you may want to have the worker thread instead post a message to a queue which you will read later, unless there is no shared state or a mutex is already in place.
In your specific example, let's add one line of code:
int main()
{
std::thread worker(foo, [](int result)
{
std::cout << "Result from worker is " << result << std::endl;
});
std::cout << "I am the main thread" << std::endl; // added
worker.join();
}
You might think that there are only two possible outputs:
I am the main thread
Result from worker is 5
and
Result from worker is 5
I am the main thread
But in fact there are other possible outputs, such as:
Result from worker is I am the main thread
5
So you have created a bug. You either need synchronization on your shared state (which includes I/O), or you need to orchestrate everything from the main thread (which is what blocking or checking for a future result gives you).

C++11 - Managing worker threads

I am new to threading in C++11 and I am wondering how to manage worker threads (using the standard library) to perform some task and then die off. I have a pool of threads vector<thread *> thread_pool that maintains a list of active threads.
Let's say I launch a new thread and add it to the pool using thread_pool.push_back(new thread(worker_task)), where worker_task is defined as follows:
void worker_task()
{
this_thread::sleep_for(chrono::milliseconds(1000));
cout << "Hello, world!\n"
}
Once the worker thread has terminated, what is the best way to reliably remove the thread from the pool? The main thread needs to run continuously and cannot block on a join call. I am more confused about the general structure of the code than the intricacies of synchronization.
Edit: It looks like I misused the concept of a pool in my code. All I meant was that I have a list of threads that are currently running.
You can use std::thread::detach to "separate the thread of execution from the thread object, allowing execution to continue independently. Any allocated resources will be freed once the thread exits."
If each thread should make its state visible, you can move this functionality into the thread function.
std::mutex mutex;
using strings = std::list<std::string>;
strings info;
strings::iterator insert(std::string value) {
std::unique_lock<std::mutex> lock{mutex};
return info.insert(info.end(), std::move(value));
}
auto erase(strings::iterator p) {
std::unique_lock<std::mutex> lock{mutex};
info.erase(p);
}
template <typename F>
void async(F f) {
std::thread{[f] {
auto p = insert("...");
try {
f();
} catch (...) {
erase(p);
throw;
}
erase(p);
}}.detach();
}

Keeping threads alive even if the main thead has terminated

I am not sure if my question is correct, but I have the following example, where the main thread creates two additional threads.
Since I am not using join command at the end of the main, it will continue execution and in the same time, the two created threads will work in parallel. But since the main is terminated before they finish their execution, I am getting the following output:
terminate called without an active exception
Aborted (core dumped)
Here's the code:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <chrono>
void foo()
{
std::chrono::milliseconds dura( 2000 );
std::this_thread::sleep_for( dura );
std::cout << "Waited for 2Sec\n";
}
void bar(int x)
{
std::chrono::milliseconds dura( 4000 );
std::this_thread::sleep_for( dura );
std::cout << "Waited for 4Sec\n";
}
int main()
{
std::thread first (foo);
std::thread second (bar,0);
return 0;
}
So my question is how to keep these two threads working even if the main thread terminated?
I am asking this because in my main program, I have an event handler ,and for each event I create a corresponding thread. But the main problem when the handler creates a new thread, the handler will continue execution. Until it is destroyed which will cause also the newly created thread to be destroyed. So my question is how to keep the thread alive in this case?
Also if I use a join it will convert back to serialization.
void ho_commit_indication_handler(message &msg, const boost::system::error_code &ec)
{
.....
}
void event_handler(message &msg, const boost::system::error_code &ec)
{
if (ec)
{
log_(0, __FUNCTION__, " error: ", ec.message());
return;
}
switch (msg.mid())
{
case n2n_ho_commit:
{
boost::thread thrd(&ho_commit_indication_handler, boost::ref(msg), boost::ref(ec));
}
break
}
};
Thanks a lot.
Keeping the threads alive is a bad idea, because it causes a call to std::terminate. You should definitively join the threads:
int main()
{
std::thread first (foo);
std::thread second (bar, 0);
first.join();
second.join();
}
An alternative is to detach the threads. However you still need to assert that the main thread lives longer (by e.g. using a mutex / condition_variable).
This excerpt from the C++11 standard is relevant here:
15.5.1 The std::terminate() function [except.terminate]
1 In some situations exception handling must be abandoned for less subtle error
handling techniques. [ Note: These situations are:
[...]
-- when the destructor or the copy assignment operator is invoked on an
object of type std::thread that refers to a joinable thread
Hence, you have to call either join or detach on threads before scope exit.
Concerning your edit: You have to store the threads in a list (or similar) and wait for every one of them before main is done. A better idea would be to use a thread pool (because this limits the total number of threads created).

Controlling a camera from Qt: interaction of OS threads with the event loop

I'm working on a Qt application to control an industrial camera, and in particular I need to trigger the camera at a particular time (when various illumination settings have been put in place, for example), and wait until a frame is returned. In the simplest case, the following code does the job nicely:
void AcquireFrame()
{
// Runs in the main GUI thread:
camera -> m_mutex.lock();
camera -> frameHasArrived = false;
camera -> m_mutex.unlock();
camera -> triggerImageAcquisition();
forever
{
camera -> m_mutex.lock()
bool isReady = camera -> frameHasArrived;
camera -> m_mutex.unlock()
if (isReady)
{
return;
}
else
{
Sleep(10);
}
}
}
void callback(camera *)
{
// Called by the camera driver from a separate OS thread - not a Qt thread -
// when a frame is ready:
camera -> m_mutex.lock();
camera -> frameHasArrived = true;
camera -> m_mutex.unlock();
}
...and most of the time this works perfectly well. However, this being the real world, occasionally the camera will fail to receive the trigger or the computer will fail to receive the frame cleanly, and the above code will then go into an infinite loop.
The obvious thing to do is to put in a timeout, so if the frame is not received within a certain time then the image acquisition can be attempted again. The revised code looks like:
void AcquireFrame()
{
camera -> m_mutex.lock();
camera -> frameHasArrived = false;
camera -> m_mutex.unlock();
camera -> triggerImageAcquisition();
QTime timeout;
timeout.start();
forever
{
timeout.restart();
fetch: camera -> m_mutex.lock()
bool isReady = camera -> frameHasArrived;
camera -> m_mutex.unlock()
if (isReady)
{
return;
}
else if (timeout.elapsed() > CAM_TIMEOUT)
{
// Assume the first trigger failed, so try again:
camera -> triggerImageAcquisition();
continue;
}
else
{
Sleep(10);
goto fetch;
}
}
}
Now, the problem is that with this latter version the failure rate (the proportion of 'unsuccessful triggers') is much, much higher - at least an order of magnitude. Moreover, this code too will eventually find itself in an infinite loop where, however many times it tries to re-trigger the camera, it never sees a frame come back. Under these latter circumstances, killing the application and checking the camera reveals that the camera is in perfect working order and patiently waiting for its next trigger, so it doesn't appear to be a camera problem. I'm coming to the conclusion that in fact it's some sort of a system resource issue or a thread conflict, so that Qt's event loop is not allowing the camera callback to be called at the proper time.
Is this likely, and is there in fact a better way of doing this?
Update on 6th June:
For what it's worth, I've seen no more problems since I adopted the method below (having given the camera object an extra member, namely a QWaitCondition called 'm_condition'):
void AcquireFrame()
{
bool frameReceived;
forever
{
camera -> triggerImageAcquisition();
camera -> m_mutex.lock();
frameReceived = camera -> m_condition.wait(&camera->m_mutex, CAM_TIMEOUT);
if (frameReceived)
{
// We received a frame from the camera, so can return:
camera -> m_mutex.unlock();
return;
}
// If we got to here, then the wait condition must have timed out. We need to
// unlock the mutex, go back to the beginning of the 'forever' loop and try
// again:
camera -> m_mutex.unlock();
}
}
void callback (camera *)
{
// Called by the camera driver from a separate OS thread -
// not a QThread - when a frame is ready:
camera -> m_condition.wakeOne();
}
This still has the effect of pausing the main thread until we have either received a frame or experienced a timeout, but now we have eliminated the Sleep() and the Qt event loop remains in full control throughout. It's still not clear to me why the old method caused so many problems - I still suspect some sort of system resource limitation - but this new approach seems to be more lightweight and certainly works better.
Running the AcquireFrame that blocks on mutexes in the GUI thread makes not much sense to me unless you wanted to trade off GUI reponsiveness for latency, but I doubt that you care about the latency here as the camera snaps single frames and you insist on processing them in the busy GUI thread in the first place.
Secondly, there is nothing that Qt would do to prevent the callback from getting called from the other thread, other than the other thread having lower priority and being preempted by higher priority threads completely monopolizing the CPU.
I would simply post an event to a QObject in the GUI thread (or any other QThread!) from the callback function. You can post events from any thread, it doesn't matter -- what matters is the receiver. QCoreApplication::postEvent is a static function, after all, and it doesn't check the current thread at all.
In a complex application you probably want to have the logic in a dedicated controller QObject, and not spread across QWidget-derived classes. So you'd simply post the event to the controller instance.
Do note that posting an event to an idle GUI thread will work exactly the same as using a mutex -- Qt's event loop uses a mutex and sleeps on that mutex and on messages from the OS. The beautiful thing is that Qt already does all the waiting for you, but the wait is interruptible. The posted event should have a high priority, so that it'll end up the first one in the queue and preempt all the other events. When you're ready to acquire the frame, but before you trigger it, you can probably call QCoreApplication::flush(). That's about it.
There should be no problem in having a separate image processor QObject living in a dedicated QThread to leverage multicore machines. You can then process the image into a QImage, and forward that one to the GUI thread using another event, or simply via a signal-slot connection. You can probably also notify the GUI thread when you've acquired the frame but are only beginning to process it. That way it'd be more obvious to the user that something is happening. If image processing takes long, you can even send periodic updates that'd be mapped to a progress bar.
The benchmark results (using release builds) are interesting but in line with the fact that Qt's event queues are internally protected by a mutex, and the event loop waits on that mutex. Oh, the results seem to be portable among mac and windows xp platforms.
Using a naked wait condition is not the fastest way, but using a naked posted event is even slower. The fastest way is to use a queued signal-slot connection. In that case, the cost of posting an event to the same thread (that's what the FrameProcessorEvents::tick() does) seems to be negligible.
Mac
warming caches...
benchmarking...
wait condition latency: avg=45us, max=152us, min=8us, n=1001
queued signal connection latency: avg=25us, max=82us, min=10us, n=1000
queued event latency: avg=71us, max=205us, min=14us, n=1000
Windows XP under VMWare Fusion
Note that results over 1ms are likely due to VMWare being not scheduled at the moment.
warming caches...
benchmarking...
wait condition latency: avg=93us, max=783us, min=8us, n=1000
queued signal connection latency: avg=46us, max=1799us, min=0us, n=1000
queued event latency: avg=117us, max=989us, min=18us, n=1001
Below is the benchmarking code.
#include <cstdio>
#include <limits>
#include <QtCore>
QTextStream out(stdout);
class TimedBase : public QObject
{
public:
TimedBase(QObject * parent = 0) : QObject(parent) { reset(); }
friend QTextStream & operator<<(QTextStream & str, const TimedBase & tb) {
return str << "avg=" << tb.avg() << "us, max=" << tb.usMax << "us, min="
<< tb.usMin << "us, n=" << tb.n;
}
void reset() { usMax = 0; n = 0; usMin = std::numeric_limits<quint32>::max(); usSum = 0; }
protected:
quint64 n, usMax, usMin, usSum;
quint64 avg() const { return (n) ? usSum/n : 0; }
void tock() {
const quint64 t = elapsed.nsecsElapsed() / 1000;
usSum += t;
if (t > usMax) usMax = t;
if (t < usMin) usMin = t;
n ++;
}
QElapsedTimer elapsed;
};
class FrameProcessorEvents : public TimedBase
{
Q_OBJECT
public:
FrameProcessorEvents(QObject * parent = 0) : TimedBase(parent) {}
public slots: // can be invoked either from object thread or from the caller thread
void tick() {
elapsed.start();
QCoreApplication::postEvent(this, new QEvent(QEvent::User), 1000);
}
protected:
void customEvent(QEvent * ev) { if (ev->type() == QEvent::User) tock(); }
};
class FrameProcessorWait : public TimedBase
{
Q_OBJECT
public:
FrameProcessorWait(QObject * parent = 0) : TimedBase(parent) {}
void start() {
QTimer::singleShot(0, this, SLOT(spinner()));
}
public: // not a slot since it must be always invoked in the caller thread
void tick() { elapsed.start(); wc.wakeAll(); }
protected:
QMutex mutex;
QWaitCondition wc;
protected slots:
void spinner() {
forever {
QMutexLocker lock(&mutex);
if (wc.wait(&mutex, 1000)) {
tock();
} else {
return;
}
}
}
};
FrameProcessorEvents * fpe;
FrameProcessorWait * fpw;
static const int avgCount = 1000;
static const int period = 5;
class FrameSender : public QObject
{
Q_OBJECT
public:
FrameSender(QObject * parent = 0) : QObject(parent), n(0), N(1) {
QTimer::singleShot(0, this, SLOT(start()));
}
protected slots:
void start() {
out << (N ? "warming caches..." : "benchmarking...") << endl;
// fire off a bunch of wait ticks
n = avgCount;
timer.disconnect();
connect(&timer, SIGNAL(timeout()), SLOT(waitTick()));
fpw->reset();
fpw->start();
timer.start(period);
}
void waitTick() {
fpw->tick();
if (!n--) {
if (!N) { out << "wait condition latency: " << *fpw << endl; }
// fire off a bunch of signal+event ticks
n = avgCount;
fpe->reset();
timer.disconnect();
connect(&timer, SIGNAL(timeout()), fpe, SLOT(tick()));
connect(&timer, SIGNAL(timeout()), SLOT(signalTick()));
}
}
void signalTick() {
if (!n--) {
if (!N) { out << "queued signal connection latency: " << *fpe << endl; }
// fire off a bunch of event-only ticks
n = avgCount;
fpe->reset();
timer.disconnect();
connect(&timer, SIGNAL(timeout()), SLOT(eventTick()));
}
}
void eventTick() {
fpe->tick();
if (!n--) {
if (!N) { out << "queued event latency: " << *fpe << endl; }
if (!N--) {
qApp->exit();
} else {
start();
}
}
}
protected:
QTimer timer;
int n, N;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThread eThread;
QThread wThread;
eThread.start(QThread::TimeCriticalPriority);
wThread.start(QThread::TimeCriticalPriority);
fpw = new FrameProcessorWait();
fpe = new FrameProcessorEvents();
fpw->moveToThread(&eThread);
fpe->moveToThread(&wThread);
FrameSender s;
a.exec();
eThread.exit();
wThread.exit();
eThread.wait();
wThread.wait();
return 0;
}
#include "main.moc"
How much work is it to detect the trigger state and fire the camera?
If that's relatively cheap - I would have a separate thread just blocking on a trigger event and firing the camera. Then have the main thread informed by a Qt signal sent from the callback function.

Resources