multithreaded Qt+OpenCV - c++

I am going to make a thread which recieves the image from webcam camera, using opencv and Mat type. then I convert it to QImage and send it to main thread using a signal. when I want to visualize it in a QLabel object in ui (after converting to a pixmap) I get this error:
The program has unexpectedly finished.
here is my camera class:
camera.h:
#ifndef CAMERA_H
#define CAMERA_H
#include <QObject>
#include <QThread>
#include <QtCore>
#include <QtGui>
#include <opencv2/opencv.hpp>
using namespace cv;
class Camera: public QThread
{
Q_OBJECT
public:
Camera();
void run();
bool Stop = false;
signals:
void ImgSignal(QImage*);
private:
public slots:
};
#endif // THREAD_H
camera.cpp:
#include "camera.h"
#include <iostream>
using namespace std;
Camera::Camera()
{
}
void Camera::run()
{
VideoCapture cap;
cap.open(0);
while(1){
Mat img;
cap >> img;
cvtColor(img,img,CV_BGR2RGB);
QImage image = QImage((const uchar*)img.data,img.cols,img.rows,img.step,QImage::Format_RGB888);
emit ImgSignal(&image);
QThread::msleep(30);
}
}
and finally my onImgSignal function that recieves the image and passes it to gui:
void MainWindow::onImgSignal(QImage *img)
{
QPixmap *p;
p->fromImage(*img);
ui->label->setPixmap(*p);
}
I would be so glad if you help me. thanks!
Edit
when I changed the pixmap poiner to a pixmap variable the error did not come up but the pixmap variable is null. even if i load an image separately it will be null:
QPixmap p;
p.load("mark.png");
cout << p.isNull();
ui->label->setPixmap(p);

My first hunch is that some pointer to some object/memory are accidentally accessed by two different threads at the same time, creating an access violation. So by just making a COPY of the image you pass around might do the trick (so both threads arn't accessing the pixel data of the same image at the same time). Here are some other things you can do to address that:
First, the threads implementation in Qt is a bit unconventional. For example, it is not considered best practice to extend the QThread class like you have done, as the QThread instance will NOT live in the new OS level thread. Yes! It's true. This leads to many sources of confusion that in turn lead to bugs. To read the official unofficial guide on how to do threads correctly in Qt, please look at this excellent article. Short summary: QThread class will act as a "management" class living in the execution thread where you instantiated it, so first tip is to learn this, and use the QThread class as intended.
Second, Qt is supposed to guess during signal time when the source and destination are in same thread or not, however I have found that it sometimes, just for the peace of mind, pays to be specific about how signals will be passed. That is why my code is full of this:
if(!connect(this,SIGNAL(colorChanged(QColor)),&ob,SLOT(onColorChanged(QColor)),(Qt::ConnectionType) (Qt::QueuedConnection | Qt::UniqueConnection) )) {
qWarning()<<"ERROR: Could not connect "<<ob.objectName();
}
Notice the last parameter to the connect call, as it specifies Qt::QueuedConnection and Qt::UniqueConnection connections. Qt::QueuedConnection means that it is "thread safe" in that it will store the signal in a thread safe FIFO. Qt::UniqueConnection just means that connecting twice will generate an error the second time instead of creating two connections (which may lead to hard-to-trace bugs).
Third, are you starting any threads without using Qt? In that case care should be taken with signals, because they might not work properly unless you are working with Qt initiated threads. I THINK the Qt::QueuedConnection trick above should be enough, but I don't know. Here is more. Oh, and if OpenCV ever decides to knowingly or unknowingly start some threads of it's own, they will count as "threads started outside Qt".
Fourth, did you run this in a debugger? At what exact point did it crash? This should be your first move, btw.
Fifth, If all else fails wrap your code in a QMutex and use QMutexLocker to ensure that there is no problems. Or you could get fancy and use some thread safe containers or some such.
PS: Please let me know how you fare!

Related

Qt Application Memory Usage

I'm working on an application that involves using real time, continuous, audio input, for which I'm using portaudio. I created simple cli version first in order to set things up and the memory usage in the cli version seemed fine. In the CLI version, while the recording was on, no extra memory was being allocated aside from the initial buffer.
However, in the process of applying the same code from the CLI to a GUI (for which, I'm using Qt), I notice that as the recording proceeds, the memory being used by the application constantly increases (by about 3 mb/sec). Since my application involves audio input for an undefined amount of time, such behaviour can be extremely fatal and thus,I started stripping off segments from the code inorder to check which area was responsible for this memory being used. (note that this behavior was NOT being observed from the cli version, and that nearly the same code was used in qt, aside from the addition of a Q_OBJECT macro)
I tried this for a while but could not find anything.
I am relatively new to using Qt and would greatly appreciate some help with this
My widget apps header file
#ifndef DETECTORMAIN_H
#define DETECTORMAIN_H
#include <QMainWindow>
#include <QThread>
#include <QPointer>
#include "utils/rectools.h" /*Custom header file, the implementation of
which has been carried over from the cli version
which worked with constant memory usage.
Contains a class Recorder with the Q_OBJECT macro*/
QT_BEGIN_NAMESPACE
namespace Ui { class detectorMain; }
QT_END_NAMESPACE
class detectorMain : public QMainWindow
{
Q_OBJECT
public:
detectorMain(QWidget *parent = nullptr);
~detectorMain();
private slots:
void on_beginRecordingButton_clicked();
void on_stopRecordingButton_clicked();
void updateVolLabel(std::string);
private:
Ui::detectorMain *ui;
QPointer<Recorder> recorder;
QThread* thread;
};
#endif // DETECTORMAIN_H
Source file
#include "detectormain.h"
#include "ui_detectormain.h"
detectorMain::detectorMain(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::detectorMain)
{
ui->setupUi(this);
recorder = new Recorder;
thread = new QThread;
recorder->moveToThread(thread);
thread->start();
ui->beginRecordingButton->setEnabled(true);
ui->stopRecordingButton->setEnabled(false);
connect(recorder, SIGNAL(UpdateVols(std::string)), this, SLOT(updateVolLabel(std::string)));
}
detectorMain::~detectorMain()
{
delete ui;
}
void detectorMain::on_beginRecordingButton_clicked()
{
ui->beginRecordingButton->setEnabled(false);
ui->stopRecordingButton->setEnabled(true);
recorder->begin_recording();
}
void detectorMain::on_stopRecordingButton_clicked()
{
recorder->stop_recording();
ui->beginRecordingButton->setEnabled(true);
ui->stopRecordingButton->setEnabled(false);
}
void detectorMain::updateVolLabel(std::string vol)
{
ui->VolLabel->setText(QString::fromStdString(vol));
QCoreApplication::processEvents();
}
The function Recorder::begin_recording() emits UpdateVols(std::string) where UpdateVols is a signal in the Recorder class. It emits at a pretty fast rate (around 1 every ms). Does this have something to with the memory usage increasing?
In the CLI version I could just cout whatever I needed to and this is the most major difference in code between the CLI version and the Qt version.
The memory usage does not reduce after the begin_recording() function has finished execution though which confuses me.
For example, the app starts at 9 mb memory usage, increases to about 39 when begin_recording() runs for 10 seconds, and stays at 39mb when not doing anything afterwards.
If it was the fast emit rate, I assume that the memory usage will return to normal when it is no longer emitting.
Additionally, in the above code, when the beginRecordingButton is clicked, the app becomes unresponsive, but resumes once the function recorder->begin_recording() has finished execution. I guess this has something to do with the memory increasing constantly but I'm not too sure.
I believe the error to lie somewhere in how I'm using the QThread object and moving the recorder object to it, but I'm not sure how to fix it.
In the process of finding out where the memory usage was being increased, I tried running a bare app with just the buttons and labels, not involving the recorder class at all. On simply opening this app with zero functionality, the memory usage kept increasing by about 0.5mb whenever it showed a non zero CPU utilization. After increasing, it does not fall down even if the cpu utilisation was 0.
Overall, I would like to ask,
1)How can I fix the issue of the memory usage constantly increasing? (I don't think the error lies in the Recorder class as the same code runs without qt at constant memory)
2)Is the behavior mentioned in the final paragraph normal?
What #G.M. said in the comments worked. Thank You
The problem was the emit rate. 1khz is too fast and a lot gets build up.

How to use threads in Qt GUI

I have an application that continuously reads an image from a camera and displays this to a user. The user can adjust different sliders such as exposure and threshold to modify the image in real-time. I also do a bunch of calculations on this image afterwards which sometimes makes the GUI unresponsive, so I decided to use threads to divide the workload.
However, I can't get it to work properly, sometimes I get segmentation faults and a bunch of "assertion ` GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed" warnings when the slider values are changed or if I try to save the image (save button in my GUI), and the GUI sometimes stops updating the image or freezes so you can't move the sliders or push any buttons.
What I tried to do was to use the standard std::thread in C++, and connect it to the start button through a slot.
QObject::connect(btnStart, SIGNAL(clicked()), this, SLOT(RunStartThread()));
void MainMenu::RunStartThread(){
std::thread t1;
t1= std::thread(&MainMenu::Start,this);
t1.detach();
}
void MainMenu::Start() {
run = true;
window->mngr->ReadCalibration();
window->mngr->InitializeCameras();
while (run) {
window->mngr->CaptureImage();
window->mngr->ProcessImages();
UpdateLabels();
}
window->mngr->Stop();
}
When the user changes the slider values they change variables in my manager (mngr above) that captureImage and ProcessImages uses. I tried using a std::mutex lock/unlock when a variable was to be accessed, but it did not change anything. I've tried to find examples of how to do this online, but have yet to find something that has a continuous while-loop.
I'm a newbie when it comes to threads, so just tell me if I'm approaching this in the wrong way.
First for all for inter thread communication use singnals and slots. By default Qt connections do nice thread hopping between threads which lets to avoid complex synchronization.
Secondly you have three ways of using threads: QThread, QRunnable, QtConcurrent::Run (my favorite, since requires minimum amount of code).
In case QThread please do not subclass it! It is common design mistake.
Example:
SomeClass::~SomeClass()
{
SignalStop();
future.result();
}
void SomeClass::RunStartThread(){
future = QtConcurrent::run(this, &SomeClass::DoOnThread);
}
void SomeClass::DoOnThread()
{
while (ShouldContinueToRun()) {
QImage im1 = CaptureImage();
emit ImageCaptured(im1);
QImage im2 = ProcessImages(im1);
emit ImageProcessed(im2);
}
emit JobCompleted();
}
Please note that QObject::connect has last argument which defines how invocation of slot is performed if different thread is involved. See documentation of enumeration used for this argument.
So by default Qt detects if thread hopping is needed or not. Reading carefully about QObject::moveToThread should also help to understand the problem (note you can't move object to different thread if it has a parent).

Qt - updating main window with second thread

i have an multithreaded qt application. when i am doing some processes in mainwindow.cpp, at the same time, i want to update mainwindow.ui from other thread.
i have mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include "mainwindow.h"
class mythread : public QThread
{
public:
void run();
mythread( MainWindow* ana );
MainWindow* ana;
private:
};
#endif // MYTHREAD_H
mythread.cpp
mythread::mythread(MainWindow* a)
{
cout << "thread created" << endl;
ana = a;
}
void mythread::run()
{
QPixmap i1 (":/notes/pic/4mdodiyez.jpg");
QLabel *label = new QLabel();
label->setPixmap(i1);
ana->ui->horizontalLayout_4->addWidget(label);
}
but the problem is that, i cannot reach the ana->ui->horizontalLayout_4->addWidget(label);
how can i do that?
but the problem is that, i cannot reach the
ana->ui->horizontalLayout_4->addWidget(label);
Put your UI modifications in a slot in your main window, and connect a thread signal to that slot, chances are it will work. I think only the main thread has access to the UI in Qt. Thus if you want GUI functionality, it must be there, and can be only signaled from other threads.
OK, here is a simple example. BTW, your scenario doesn't really require to extend QThread - so you are better off not doing it, unless you really have to. That is why in this example I will use a normal QThread with a QObject based worker instead, but the concept is the same if you subclass QThread:
The main UI:
class MainUI : public QWidget
{
Q_OBJECT
public:
explicit MainUI(QWidget *parent = 0): QWidget(parent) {
layout = new QHBoxLayout(this);
setLayout(layout);
QThread *thread = new QThread(this);
GUIUpdater *updater = new GUIUpdater();
updater->moveToThread(thread);
connect(updater, SIGNAL(requestNewLabel(QString)), this, SLOT(createLabel(QString)));
connect(thread, SIGNAL(destroyed()), updater, SLOT(deleteLater()));
updater->newLabel("h:/test.png");
}
public slots:
void createLabel(const QString &imgSource) {
QPixmap i1(imgSource);
QLabel *label = new QLabel(this);
label->setPixmap(i1);
layout->addWidget(label);
}
private:
QHBoxLayout *layout;
};
... and the worker object:
class GUIUpdater : public QObject {
Q_OBJECT
public:
explicit GUIUpdater(QObject *parent = 0) : QObject(parent) {}
void newLabel(const QString &image) { emit requestNewLabel(image); }
signals:
void requestNewLabel(const QString &);
};
The worker object is created and moved to another thread, then connected to the slot that creates the labels, then its newLabel method is invoked, which is just a wrapper to emit the requestNewLabel signal and pass the path to the image. The signal is then passed from the worker object/thread to the main UI slot along with the image path parameter and a new label is added to the layout.
Since the worker object is created without parent in order to be able to move it to another thread, we also connect the thread destroyed signal to the worker deleteLater() slot.
First and foremost, "you're doing it wrong". Normally you want to create a class derived from a QObject and move that class to a new thread object instead of deriving your class from a Qthread
Now to get onto the specifics of your question, you're not able to directly modify the ui elements of your main GUI thread from a separate thread. You have to connect a signal from your 2nd thread to a slot in your main thread. You can pass any data that you need through this signal/slot connection but you're unable to directly modify the ui element (which in all honestly you probably do not want to if you intend to keep the frontend of your app separate from the backend). Checkout Qt's signal and slot documentation for a whole lot more information
how can i do that?
You've already got the answers to what you should be doing, but not a why, so I'm going to add a why.
The reason you don't modify GUI elements from another thread is because GUI elements are usually not thread-safe. This means that if both your main GUI thread and your worker thread update the UI, you cannot be certain of the order of what happened when.
For reading data generally this can sometimes be fine (e.g. checking a condition) but generally you do not want this to be case. For writing data, this is almost always the source of very, very stressful bugs which occur "at random".
Another answer has remarked on good design principles - not only does constraining your GUI logic to one thread and firing signals to talk to it get rid of your race condition issues, but it also forces you to compartmentalize your code nicely. Presentation logic (the display bit) and data processing logic can then be cleanly separated out, which makes maintaining the two much easier.
At this stage you might think: heck, this threads business is farrrrrr too much work! I'll just avoid that. To see why this is a bad idea, implement a file copy program in a single thread with a simple progress bar telling you how far along the copy is. Run it on a large file. On Windows, after a while, the application will "go white" (or on XP I think it goes gray) and will be "not responding". This is very literally what is happening.
GUI applications internally mostly work on the variation of "one big loop" processing and dispatching messages. Windows, for example, measures response time to those messages. If a message takes too long to get a response, Windows then decides it is dead, and takes over. This is documented in GetMessage().
So whilst it may seem like quite a bit of work, Signals/Slots (an event-driven model) is basically the way to go - another way to think of this is that it is totally acceptable for your threads to generate "events" for the UI too - such as progress updates and the like.

Headless QT4 OpenGL Application

I'm working on creating a headless console application in QT4 that does some OpenGL rendering and then ships the result out across the network via a websocket. I have all of the rendering and network code running (assuming that I have a GUI), but I am having some trouble transitioning to a headless application. Is it possible to create a QGLContext without having a window?
Reading on the web hasn't turned up much, but from what I have gathered you can create a QGLPixelBuffer which is a valid QPaintDevice. It seems to create its own private QGLContext that it uses for hardware accelerated drawing. The problem that I am having with this route is that I need access to it's underlying QGLContext so that I can share it with another thread (network thread for fast DMA texture transfers out of the rendered scene). Included below is a small prototype. Any ideas?
Application.h
/**
#file
#author Nikolaus Karpinsky
*/
#ifndef _APPLICATION_H_
#define _APPLICATION_H_
#include <QCoreApplication>
#include <QTimer>
#include "MainController.h"
#endif // _APPLICATION_H_
Application.cpp
#include "Application.h"
int main(int argc, char **argv)
{
// Setup our console application with an event loop
QCoreApplication app(argc, argv);
// Create and initialize our controller
MainController controller;
controller.Init();
QObject::connect(&controller, SIGNAL( Finished() ), &app, SLOT( quit() ), Qt::QueuedConnection);
// This will put start on top of the event loop
QTimer::singleShot(0, &controller, SLOT( Start() ));
// Finally start up the event loop
return app.exec();
}
MainController.h
/**
#file
#author Nikolaus Karpinsky
*/
#ifndef _MAIN_CONTROLLER_H_
#define _MAIN_CONTROLLER_H_
#include <QObject>
#include <QGLWidget>
#include <QGLPixelBuffer>
#include <QGLFramebufferObject>
#include <memory>
using namespace std;
class MainController : public QObject
{
Q_OBJECT
private:
unqiue_ptr<QGLPixelBuffer> m_mainBuffer;
//unique_ptr<QGLContext> m_mainContext;
public:
MainController();
void Init(void);
public slots:
void Start(void);
void Close(void);
signals:
void Finished(void);
};
#endif // _MAIN_CONTROLLER_H_
MainController.cpp
#include "MainController.h"
MainController::MainController() : QObject()
{ }
void MainController::Init(void)
{
m_mainBuffer = unique_ptr<QGLPixelBuffer>(new QGLPixelBuffer(800, 600));
bool has = buffer->hasOpenGLPbuffers();
bool current = buffer->makeCurrent();
bool valid = buffer->isValid();
// Now I need to get access to the context to share it with additional threads
// m_mainContext = unique_ptr<QGLContext>(new QGLContext(buffer.getContext()));
}
void MainController::Start(void)
{
}
void MainController::Close(void)
{
// This will tell the event loop that we are done and close the app
emit( Finished() );
}
Is it possible to create a QGLContext without having a window?
Yes, but there is a catch…
Reading on the web hasn't turned up much, but from what I have gathered you can create a QGLPixelBuffer which is a valid QPaintDevice.
Yes, but that PBuffer still needs to talk to the GPU. And in Linux the usual way to talk to the GPU is through the X server. So you actually need an X server, using the GPUs drivers, to be launched and the active VT so that a PBuffer can work on the GPU.
Hopefully there will be a new ABI/API to GPUs soon, that allows you to create offscreen render contexts on a GPU without having an X server around.
The problem that I am having with this route is that I need access to it's underlying QGLContext so that I can share it with another thread (network thread for fast DMA texture transfers out of the rendered scene).
Unfortunately the Qt developers have only limited knowledge about OpenGL, as it seems. Several things that are perfectly possible with OpenGL and well specified are not possible with Qt for no apparent reason. For example you can have an arbitrary number of contexts using a single drawable. But you can also use single context on an arbitrary number of (compatible) drawables by rebinding it. Neither is supported by Qt and a clear design flaw. I'm struggling with this myself right now.
Ok, so after some playing around I found a good enough solution. Currently I am running my application as a QApplication vs QCoreApplication. From here I create a QGLWidget on the GUI thread and then immediately call updateGL() on the widget which creates and initalizes the OpenGL context. Assuming I don't ever make the app visible it runs "headless" but still gets the QT needed window handle from X or Explorer.
Going a bit deeper, I also needed to get shared QGLContexts on other threads. To make copies of the context from the QGLWidget I simply create a QGLWidget using the deprecated constructor where you can specify a painter (QGLWidget) and then create using the QGLWidgets context. I posted an example below to show. Using this I can write textures in one thread and process in another while keeping the app "headless". Thanks for the help datenwolf.
shared_ptr<QGLContext> MainController::MakeSharedContext(void)
{
shared_ptr<QGLContext> sharedContext(nullptr);
if(nullptr != m_mainContext)
{
// m_mainContext is: shared_ptr<QGLWidget>
sharedContext = shared_ptr<QGLContext>( new QGLContext(m_mainContext->format(), m_mainContext.get( ) ) );
bool created = sharedContext->create( m_mainContext->context( ) );
Utils::AssertOrThrowIfFalse(created, "Unable to create a shared OpenGL context" );
}
return sharedContext;
}

Threading issues in C++

I have asked this problem on many popular forums but no concrete response. My applciation uses serial communication to interface with external systems each having its own interface protocol. The data that is received from the systems is displayed on a GUI made in Qt 4.2.1.
Structure of application is such that
When app begins we have a login page
with a choice of four modules. This
is implemented as a maindisplay
class. Each of the four modules is a
separate class in itself. The concerned module here is of action class which is responsible of gathering and displaying data from various systems.
User authentication gets him/her
into the action screen. The
constructor of the action screen
class executes and apart from
mundane initialisation it starts the
individual systems threads which are
implemented as singleton.
Each system protocol is implemented as a singleton thread of the form:
class SensorProtocol:public QThread {
static SensorProtocol* s_instance;
SensorProtocol(){}
SensorProtocol(const SensorProtocol&);
operator=(const SensorProtocol&);
public:
static SensorProtocol* getInstance();
//miscellaneous system related data to be used for
// data acquisition and processing
};
In implementation file *.cpp:
SensorProtocol* SensorProtocol::s_instance=0;
SensorProtocol* SensorProtocol::getInstance()
{
//DOUBLE CHECKED LOCKING PATTERN I have used singletons
// without this overrated pattern also but just fyi
if(!s_instance)
{
mutex.lock();
if(!s_instance)
s_instance=new SensorProtocol();
mutex.unlock();
}
}
Structure of run function
while(!mStop)
{
mutex.lock()
while(!WaitCondition.wait(&mutex,5)
{
if(mStop)
return;
}
//code to read from port when data becomes available
// and process it and store in variables
mutex.unlock();
}
In the action screen class I have define an InputSignalHandler using sigaction and saio. This is a function pointer which is activated as soon as data arrives on any of the serial ports.
It is a global function (we cannot change it as it is specific to Linux) which is just used to compare the file descriptors of the serial port where data has arrived and the fd's of the sensor systems, if a match is found WaitCondition.wakeOne is invoked on that thread and it comes out the wait and reads and processes the data.
In the action screen class the individual threads are started as SensorProtocol::getInstance()->start().
Each system's protocol has a frame rate at which it sends data. Based on this fact, in actions screen we set up update timers to time out at refresh rate of protocols. When these timers time out the UpdateSensorProtocol() function of operation screen is called
connect(&timer, SIGNAL(timeout), this,SLOT(UpdateSensorProtocol()));
This grabs an instance of sensor singleton as
SensorProtocol* pSingleton=SensorProtocol::getInstance();
if(pSingleton->mUpdate)
{
//update data on action screen GUI
pSingleton->mUpdate=false; //NOTE : this variable is set to
// true in the singleton thread
// while one frame is processed completely
}
For all uses of singleton instance SensorProtocol::getInstance() is used. Given the above scenario, One of my protocols is hanging no matter what changes I do.
The hang occurs in the while displaying data using UpdateSensorProtocol() If I comment ShowSensorData() function in the UpdateSensorProtocol() it works fine. But otherwise it hangs and the GUI freezes. Any suggestions!
Also, Since the main thread grabs the running instance of singleton, is it really multithreading because we are essentially changing mUpdate in singleton itself albeit from action screen.
I am confused in this.
Also, Can somebody suggest an alternate design as to what I am doing now.
Thanks In Advance
First off all don't make the Systems singletons. Use some kind of Context Encapsulation
for the different system.
If you ignoe this advice and still want to create "singletons" threads at least use QApplication::instance(); as the parent of the thread and put QThread::wait() in the singleton destructors otherwise your program will crash at the program exit.
if(!s_instance){
QMutexLocker lock(&mutex);
if(!s_instance)
s_instance=new SensorProtocol( QApplication::instance());
}
But this isn't going to solve your problem ...
Qt is event driven so try to exployed this very nice event-driven architecture and create a eventloop for each system thread. Then you can create "SystemProtocols" that live in another threads and you can create timers, send events between threads, ... without using low level synchronization objects.
Have a look at the blog entry from Bradley T. Hughes Treading without the headache
Code is not compiled but should give you a good idea where to start ...
class GuiComponent : public QWidget {
//...
signals:
void start(int); // button triggerd signal
void stop(); // button triggerd singal
public slots:
// don't forget to register DataPackage at the metacompiler
// qRegisterMetaType<DataPackage>();
void dataFromProtocol( DataPackage ){
// update the gui the the new data
}
};
class ProtocolSystem : public QObject {
//...
int timerId;
signals:
void dataReady(DataPackage);
public slots:
void stop() {
killTimer(timerId);
}
void start( int interval ) {
timerId = startTimer();
}
protected:
void timerEvent(QTimerEvent * event) {
//code to read from port when data becomes available
// and process it and store in dataPackage
emit dataReady(dataPackage);
}
};
int main( int argc, char ** argv ) {
QApplication app( argc, argv );
// construct the system and glue them together
ProtocolSystem protocolSystem;
GuiComponent gui;
gui.connect(&protocolSystem, SIGNAL(dataReady(DataPackage)), SLOT(dataFromProtocol(DataPackage)));
protocolSystem.connect(&gui, SIGNAL(start(int)), SLOT(start(int)));
protocolSystem.connect(&gui, SIGNAL(stop()), SLOT(stop()));
// move communication to its thread
QThread protocolThread;
protocolSystem.moveToThread(&protocolThread);
protocolThread.start();
// repeat this for other systems ...
// start the application
gui.show();
app.exec();
// stop eventloop to before closing the application
protocolThread.quit();
protocolThread.wait();
return 0;
}
Now you have total independent systems, gui and protocols don't now each other and don't even know that the program is multithreaded. You can unit test all systems independently in a single threaded environement and just glue them together in the real application and if you need to, divided them between different threads.
That is the program architecture that I would use for this problem. Mutlithreading without a single low level synchronization element. No race conditions, no locks, ...
Problems:
Use RAII to lock/unlock your mutexes. They are currently not exception safe.
while(!mStop)
{
mutex.lock()
while(!WaitCondition.wait(&mutex,5))
{
if(mStop)
{
// PROBLEM 1: You mutex is still locked here.
// So returning here will leave the mutex locked forever.
return;
}
// PROBLEM 2: If you leave here via an exception.
// This will not fire, and again you will the mutex locked forever.
mutex.unlock();
// Problem 3: You are using the WaitCondition() incorrectly.
// You unlock the mutex here. The next thing that happens is a call
// WaitCondition.wait() where the mutex MUST be locked
}
// PROBLEM 4
// You are using the WaitCondition() incorrectly.
// On exit the mutex is always locked. So nwo the mutex is locked.
What your code should look like:
while(!mStop)
{
MutextLocker lock(mutex); // RAII lock and unlock mutex.
while(!WaitCondition.wait(&mutex,5))
{
if(mStop)
{
return;
}
//code to read from port when data becomes available
// and process it and store in variables
}
By using RAII it solves all the problems I spotted above.
On a side note.
Your double checked locking will not work correctly.
By using the static function variable suggested by 'Anders Karlsson' you solve the problem because g++ guarantees that static function variables will only be initialized once. In addition this method guaranteed that the singelton will be correctly destroyed (via destructor). Currently unless you are doing some fancy stuff via onexit() you will be leaking memory.
See here for lots of details about better implementation of singleton.
C++ Singleton design pattern
See here why your double checked locking does not work.
What are all the common undefined behaviours that a C++ programmer should know about?
I would start by using RAII (Resource Acquisition Is Initialization) to improve the safety of your locking code. You have code that look like this:
mutex.lock();
...logic...
mutex.unlock();
Wrap the mutex code inside a class where the mutex gets acquired in the ctor and released in the dtor. Now your code looks like this:
MyMutex mutex;
...logic...
The major improvement is that if any exceptions throw in the logic part, your mutex still gets released.
Also, don't let any exceptions leak out of your threads! Catch them even if you don't know how to handle them other than logging it somewhere.
I can't be completely sure what the problem is since I have no clue what the ShowSensorData() function (method?) is doing, but there are some multithreading issues with the code that you have included.
mUpdate should be protected by a mutex if it is accessed by more than one thread.
The run() method looks like it will lock the mutex and never release it if mStop is true.
You should consider using RAII practices to grab and release the mutex. I don't know if you are using Qt mutexes or not but you should look into using QMutexLocker to lock and unlock your mutexes.
I would consider changing your SensorProtocol class to use the condition variable and a flag or some sort of event (not sure what Qt has to offer here) to handle the update inside of a method associated with the object instance. Something like:
/*static*/ void
SensorProtocol::updateSensorProtocol() {
SensorProtocol *inst = SensorProtocol::getInstance();
inst->update();
}
Then make sure that the update() method grabs the mutex before reading or writing any of the members that are shared between the reader and display.
A more complete approach would be to separate your UI display, the sensors, and their linkage using a Model-View-Controller architecture. Refactoring the solution into an MVC architecture would probably simplify things quite a bit. Not to mention that it makes applications like this a lot less error-prone. Take a look at the QAbstractItemView and QAbstractItemDelegate classes for an idea on how this can be implemented. From what I remember, there is a tutorial about implementing MVC using Qt somewhere... it's been quite a few years since I have played with Qt though.
your getInstance method could maybe be written like this as well to avoid having the s_instance var:
SensorProtocol& getInstance()
{
static SensorProtocol instance;
return instance;
}
The double checked locking pattern is broken in C++. This is well documented all over the internet. I don't know what your problem is but clearly you will need to resolve this in your code.
Take a look at QextSerialPort:
QextSerialPort is a cross-platform
serial port class. This class
encapsulates a serial port on both
POSIX and Windows systems.
QextSerialPort inherits from QIODevice and makes serial port communications integrate more smoothly with the rest of the Qt API.
Also, you could use a message passing scheme for communications between the I/O and GUI threads instead of shared memory. This is often much less error prone. You can use the QApplication::postEvent function to send custom QEvent messages to a QObject to be processed in the GUI thread with the QObject::customeEvent handler. It will take care of synchronization for you and alleviate your deadlock problems..
Here is a quick and dirty example:
class IODataEvent : public QEvent
{
public:
IODataEvent() : QEvent(QEvent::User) {}
// put all of your data here
};
class IOThread : public QThread
{
public:
IOThread(QObject * parent) : QThread(parent) {}
void run()
{
for (;;) {
// do blocking I/O and protocol parsing
IODataEvent *event = new IODataEvent;
// put all of your data for the GUI into the event
qApp->postEvent(parent(), event);
// QApplication will take ownership of the event
}
}
};
class GUIObject : public QObject
{
public:
GUIObject() : QObject(), thread(new IOThread(this)) { thread->start() }
protected:
void customEvent(QEvent *event)
{
if (QEvent::User == event->type) {
IODataEvent *data = (IODataEvent *) event;
// get data and update GUI here
event->accept();
} else {
event->ignore();
}
// the event loop will release the IODataEvent memory automatically
}
private:
IOThread *thread;
};
Also, Qt 4 supports queing signals and slots across threads.
Have three sepearate threads for send, receive and display.
Raise an event whenever data is received and handle that within the display thread.
Edit in response to comment 1
I'll admit that I know nothing of qt but from what you've said it would still appear that you can create your serial port object which in turn starts up two worker threads (by use of a start method) for the input and output buffer control.
If the serial port class has a "Connect to port" method to gain use of the serial port; an "Open port" method which starts up your worker threads and opens the port; a "Close port" method to shutdown the send and receive threads and a property for setting the "On Data Received" event handler then you should be all set.
The class shouldn't need to be a singleton as you'll find that most operating systems wont allow more than one process to control a serial port at any one time, instead you'll get an exception (which you need to handle) when you try and connect if it is already in use. The worker threads ensure that the port is held under you're control.