I have Qt application, with some external library dependencies. My application and external libraries does not use threads (seems to me). There is no thread word in sources of them. One library have derivative from QTcpServer with no listen() method overloading. (OS is windows)
I create an object and call listen() method in the constructor of Window class. The warning message at console appears during listen() method call:
QObject: Cannot create children for a parent that is in a different
thread. (Parent is QJsonRpcTcpServer(0x4c1b38), parent's thread is
QThread(0x4a8d98), current thread is QThread(0x47e348)
The Qt subsystem and so on create additional threads, one of them UI thread etc. Some mesh or intersection exists or something else. After that program is not worked properly. (tcp client connect and lies until program is not closed)
What is the possible vector to debug problem?
Window::Window( QWidget *parent ) {
Service* service = new Service( parent );
QJsonRpcTcpServer* rpcServer = new QJsonRpcTcpServer( parent );
rpcServer->addService(service);
// problem at next line:
if ( rpcServer->listen(QHostAddress::Any, 42123) ) {
}
}
Some new info, when I replace QJsonRpcTcpServer with QTcpServer then warning at listen() call is disappear.
Some more new info, the problem is on windows. Build and run at FreeBSD is ok - no errors and work as expected.
How can I deal with the debug message and the fact that the worker thread prevented to start? I am getting:
"Cannot create children for a parent that is in a different thread." message in debug output.
There several ways to dynamically allocate the object and still keep track of it in Qt without using QObject base with parent (owner) passed to it. For example QScopedPointer as a member of a class of that 'parent' object instead:
/// snip ///
#include <QScopedPointer>
class Service;
class QJsonRpcTcpServer;
class Window : public QWidget
{
/// snip ///
QScopedPointer<Service> m_service;
QScopedPointer<QJsonRpcTcpServer> m_rpcServer;
};
/// snip ///
Window::Window( QWidget *parent ) {
m_service.reset(new Service( nullptr )); // unsure of default
m_rpcServer.reset(new QJsonRpcTcpServer( nullptr )); // constructor, take nullptr
m_rpcServer->addService(m_service);
// was problem at next line: not anymore
if ( m_rpcServer->listen(QHostAddress::Any, 42123) ) {
}
}
I also suspect that QJsonRpcTcpServer::addService is taking responsibility of releasing 'service' object. But that I cannot prove with docs, so try to find an answer to it as well. Mind that QScopedPointer or std::unique_ptr will always work deterministic but QObject::destroyed signal doing deferred release via QObject::deletelater is more prone to 'surprises' starting from when exactly the object gets released.
Related
A google search gives these as the top three results:
Qt: Connect inside constructor - Will slot be invoked before object is initialized?
Qt can I connect signals/slots to self in constructor?
QT Connect Signal Slot and initialize in constructor
According to those, it seems like it ought to "just work" like anything else. But this code doesn't:
EditorList::EditorList(..., QWidget* parent) :
QWidget(parent)
{
...
Processing* processing = Processing::getInstance();
connect(this, SIGNAL(reorderDelete(DataSequence*,ListType,QList<int>)), processing, SLOT(reorderDelete(DataSequence*,ListType,QList<int>)));
...
buttonDelete = new QPushButton(this);
connect(buttonDelete, SIGNAL(clicked(bool)), this, SLOT(buttonDeleteClick()));
...
}
...
void EditorList::buttonDeleteClick()
{
...
QList<int> locations;
...
emit reorderDelete(mySequence, myListType, locations); //breakpoint 1 here
}
//-----------------------------------------------------------------
void Processing::reorderDelete(DataSequence* sequence, ListType listType, QList<int> locations)
{
if(sequence) //breakpoint 2 here
{
sequence->reorderDelete(listType, locations);
}
}
The reason for this structure, instead of calling mySequence->reorderDelete directly, is to have it done in Processing's thread instead of the UI's. I hope I haven't stripped out too much detail to show the problem; this is a rather large project.
When I click my delete button, I hit breakpoint 1 (so far, so good), but I don't hit breakpoint 2. My other signals/slots work across threads, but their connects are not in constructors. I want to make this one automatic so that every instance is "just connected" without having to remember to do it. Can I not do that?
Okay, I got it. Leaving up for others to find.
According to this, my ListType enum was blocking the system from making the connection. It only works with system-known datatypes because emitting a SIGNAL actually stores a copy for the SLOT(s) to read later. I knew that, but I thought it was more like a stack frame that could take anything. Apparently not.
It also works to put a call to qRegisterMetaType<ListType>("ListType"); somewhere before the connect. (I put it in my main window's constructor.) This makes the datatype known so that the connection can work anyway.
I'm hitting both breakpoints now.
Make sure you have used Q_OBJECT macros in your class
I am working on a Desktop (Windows 7) based application and using Qt Creator v 5.6.0 for development of the Program.
I have a very strange issue i.e.
My Program crashes in DEBUG mode but works fine in RELEASE mode.
If in DEBUG mode, and I put break points to find the reason of the crash, then it doesn't crash: It work properly. But if I do not put any break points then it crashes at below code:
Project Background:
My Project includes functionality to read from the device connected at System communication port and transmits data to the MainWindow UI to display. Since to communicate with the communication port we have to use the third party library so I am not using QtSerial Port class which is much simpler and easy to use.
Code Design:
Class MainClass : In this class we have created some forms to display the data read from the device.
Class TestClass: This class will handle all the communication with the device connected at the system Serial Port and use the third party library. This class also have the while loop to read data from the device connected at Serial Port.
Since Test Class is using while loop. So we decided to make a Test Class run in different Thread.
Code for creating Thread in MainClass Constructor:
MainClass::MainClass (QWidget *parent) : QDialog(parent),
ui(new Ui::Analzyer)
{
............................
............................
workerThread = new QThread;
testClassObject = new TestClass(); // Declared in HeaderFile of MainClass
if((workerThread != NULL) && (testClassObject != NULL))
{
workerThread ->moveToThread(testClassObject );
connect(workerThread , SIGNAL(started()), testClassObject, SLOT(SomeFunc()));
connect(testClassObject, SIGNAL(exit()), workerThread , SLOT(quit()));
connect(testClassObject, SIGNAL(exit()), testClassObject, SLOT(deleteLater()));
connect(workerThread , SIGNAL(finished()), workerThread , SLOT(deleteLater()));
// connectToPort Signal is emitted when User clicks the pushbutton from // Main class UI
connect(this, SIGNAL(connectToPort(QString)), testClassObject, SLOT(openPort(QString)));
}
}
Crash Code:
void TestClass::openPort(const QString portName)
{
// Here portName is say : "Appliance Interface v2"
quint32 param2 = getParam2ForPortName(portName);
qint16 portNumber = 0;
QByteArray portNameByteArray = portName.toLatin1();
const char *portNameToOpen = portNameByteArray.data();
// Program crashed when return from this function
if(func1(portNameToOpen , param2, 10 , &portNumber) == true)
{
......................
......................
}
}
Here, I added some qDebug() and found that my code crashes when it returns from or call the func1() which is getting called in slot OpenPort(). Below is the prototype of the func1()
bool func1 (const char portDescription[], uInt32 param2,
uInt16 length, Int16 * portNr);
Since, func1() is the part of the library code. So I can not check the defination of the function func1(). I can assure that there is no problem in func1() Since it is being used in different java based projects and it works.
I did some more debugging on the Project and noticed that when in Run in DEBUG Mode with BreakPoints than in the QT Thread Debug Window I can see my connected Slot but when I do not put any breakPoint than my code crashes and in Qt Thread Debug Window I can not see my connected Slot
So, It looks the problem of connection between the Main Class and the Test Class for openPort Slot.
But I am not able to understand taht when i put breakpoints in operPort() function than I can see my openPort Slot in Qt Thread Debug window but when no breakpoints than openPort Slot is not visible in Qt Thread Debug Window and Program Crashes.
Kindly Suggest,
I can assure that there is no problem in func1() Since it is being used in different java based projects and it works.
Wait, is func1() C++ or Java ?
Also, how can you be sure it works ?
Get the library source, compile it yourself, and debug in it.
And, just to be sure, check values of your variables while debugging, and qDebug() them when not debugging
I apologise for replying on my own post but after lots of dicussion on StackOverflow and google. I was able to solve the Issue.
To Solve the Issue:
I changed the SLOT(openPort) as mentioned below:
Connect(this, SIGNAL(connectToPort(QString)), testClassObject, SLOT(openPort(QString)), Qt::DirectConnection);
That is to use the "Qt:DirectConnection" method. If we don't specify a connection method, the direct method is automatically used for connections between objects on the SAME thread.
Since here we have created a new QThread for TestClass and using a thirdParty library which might not be a thread safe.
So using "Qt::DirectConnection" make the openPort() SlOT to run in MainClass Thread. Basically, it's as if emitting the signal calls the slot method "directly".
I have an app with such structure: all the datatypes (class INode) are stored in plugins (DLLs). Some of the datatypes can be drawn (if they're IDrawable).
To load an object of, e.g. class PointCloudNode: public INode I have a special input plugin (DLL) which is called class PointCloudParser: public IIOPlugin and IIOPlugin is a thread with some specific functionality: class IIOPlugin: public QThread.
All the objects are created by NodeFactory class which is a singleton stored in separate DLL.
And here's the problem:
void PointCloudNode::update()
{
QObject::connect (this,SIGNAL(tmptmp()),this,SLOT(drawObject()));
emit tmptmp();
}
If I do this from any thread (main thread or the Input Plugin thread)
NodeFactory* fab = NodeFactory::getInstance();
boost::shared_ptr<INode> pc(fab->createNode("pointCloud","myPC"));
boost::shared_ptr<IDrawable> dr = boost::dynamic_pointer_cast<IDrawable>(pc);
dr->update();
The update launches, the tmptmp() signal is emitted, and the slot (drawObject()) executes correctly.
BUT
if do just the same, but create the object in my Input Plugin, pass over the shared pointer and execute dr->update() in another function, the slot drawObject() is never entered though all the code is executed (including connect, etc.).
To be more precise, here's the Input Plugin:
void PointCloudParserPlugin::doLoad(const QString& inputName, boost::shared_ptr<INode> container)
{
NodeFactory* factory = NodeFactory::getInstance();
boost::shared_ptr<INode> node = factory->createNode("pointCloud", inputName);
// here goes the loading itself, nothing special...
container->addChild(node); //that's the container where I keep all the objects
//boost::dynamic_pointer_cast<IDrawable>(container->getChild(inputName))->update();
//If I uncomment this line, it all works: the slot is launched.
emit loadingFinished(inputName); // it executes the following function
}
The last emit is connected to this:
void GeomBox::updateVisualization(const QString& fileName)
{
boost::shared_ptr<INode> node = container_->getChild(fileName);
boost::shared_ptr<IDrawable> nodeDrawable = boost::dynamic_pointer_cast<IDrawable>(node);
nodeDrawable->update(); //this is the problem line: update() executes, connect() works, but the slot never runs :(
}
How come? The node object is the same all the way through, it is valid. Every line in code in launched, QObject::connect doesn't write anything to debug window, the signal tmptmp() is emitted, but the slot drawObject() in one case is never reached? Any ideas?
Upd.: If I do not inherit IIOPlugin from QThread, everything works fine (i.e. load the object in the main thread). I expected the signals/slots to work across the threads...
Since you are sending a signal across to a different thread, you might need to explicitly tell Qt that the connection should be a queued one:
QObject::connect(this, SIGNAL(tmptmp()), this, SLOT(drawObject()), Qt::QueuedConnection );
By default Qt will use Qt::AutoConnection as that last parameter, and it will choose whether to use a direct connection (if the slot is in the same thread as the emitter) or a queued connection (if the slot is in a different thread). But since your thread is in a separate library, maybe Qt isn't making the right assumption here.
My program has one dialog and two sockets. Both sockets are derived from CAsyncSocket, one is for listening, other is for receiving data from client. My program crashes when client tries to connect to server application and server needs to initialize receiving socket.
This is my MFC dialog class.
class CFileTransferServerDlg : public CDialog
{
...
ListeningSocket ListenSock;
ReceivingSocket* RecvSock;
void OnAccept(); // called when ListenSock gets connection attempt
...
};
This is my derived socket class for receiving data that calls parent dialogs method when event is signaled.
class ReceivingSocket : public CAsyncSocket
{
...
CFileTransferServerDlg* m_pDlg; // for accessing parent dialogs controls
virtual void OnReceive(int nErrorCode);
...
}
ReceivingSocket::ReceivingSocket()
{
}
This is dialogs function that handles incoming connection attempt when listening socket gets event notification. This is where the crash happens.
void CFileTransferServerDlg::OnAccept()
{
RecvSock = new ReceivingSocket; /* CRASH */
}
OR
void CFileTransferServerDlg::OnAccept()
{
ReceivingSocket* tmpSock = new ReceivingSocket;
tmpSock->SetParentDlg(this);
CString message;
if( ListenSock.Accept(*tmpSock) ) /* CRASH */
{
message.LoadStringW(IDS_CLIENT_CONNECTED);
m_txtStatus.SetWindowTextW(message);
RecvSock = tmpSock;
}
}
My program crashes when I try to create a socket for receiving file sent from client application. OnAccept starts when Listening socket signals incoming connection attempt, but my application then crashes. What could be wrong?
Error in debug mode:
Unhandled exception at 0x009c30e1 in FileTransferServer.exe: 0xC0000005: Access violation reading location 0xccccce58.
UPDATE:
I edited code a little and I've found that inside sockcore.cpp where Accept is defined, program failes on this line of code:
ASSERT(rConnectedSocket.m_hSocket == INVALID_SOCKET);
I don't understand how that can happen. ReceivingSocket class is somehow not getting constructed right. I derive it from CAsyncSock, leave constructor empty, and no matter where I create it, on stack or on heap, it always crashes.
Here is complete project, both client and server, if anyone can take a look at it I would be really grateful. I apologize for the comments, they are in Croatian.
Visual Studio project
I've looked into your code. The issue seems to be that you never call ListeningSocket::SetParentDlg(CFileTransferServerDlg* parent). Since you also do not initialize the m_pDlg pointer in the ListeningSocket constructor, it has random values and the program might crash here and there when you access this pointer. (I had also a crash but slightly at another location than you pointed out.)
I've changed it this way:
In ListeningSocket.h changed the constructor:
ListeningSocket(CFileTransferServerDlg* parent);
Also in ListeningSocket.cpp:
ListeningSocket::ListeningSocket(CFileTransferServerDlg* parent)
: m_pDlg(parent)
{
}
Constructor of CFileTransferServerDlg changed this way:
CFileTransferServerDlg::CFileTransferServerDlg(CWnd* pParent /*=NULL*/)
: CDialog(CFileTransferServerDlg::IDD, pParent),
ListenSock(this)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
Crash disappeared.
Other ways are possible of course.
Really nice little programs, by the way :) I'll delete them of course now since I can't probably afford the license fees :)
Maybe check to see if you've inherited ReceivingSocket correctly?
Check this out.
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.