in my C++ based BlackBerry 10 app I have a custom class that uses QNetworkAccessManager to handle network connections. The requestFinished(..) method of QNetworkAccessManager object emits a signal when it receives some data.
The thing is, many outside classes are interested in this signal. So, I have many slots connected to this signal. My problem is that, in those slots, I may be doing some UI related stuff -- so I may not want that once the signal is emitted, ALL slots get called simultaneously all the time.
Rather I may want that, at one point in time, the signal calls only one slot, at another point in time, another slot, and etc. What are the ways to do this???
I thought I could do is using different QNetworkAccessManager objects (below) -- but I have heard it is not recommended??? e.g., what are other ways??? Thank you.
MyNetworkClass *network1 = new MyNetworkClass();
bool res = QObject::connect(network1, SIGNAL(signalSuccess(QVariant)), this, SLOT(CustomSLot1(QVariant)));
MyNetworkClass *network2 = new MyNetworkClass();
bool res = QObject::connect(network2, SIGNAL(signalSuccess(QVariant)), this, SLOT(CustomSLot2(QVariant)));
MyNetworkClass *network3 = new MyNetworkClass();
bool res = QObject::connect(network3, SIGNAL(signalSuccess(QVariant)), this, SLOT(CustomSLot3(QVariant)));
By default, Qt application runs only 1 thread. This means nothing can be asyncronous. When one signal is fired, the slot function is run before anything else happens.
If you want to keep UI responsive and handle 3 functions at the same time, you need to thread them. At the beginning of the slot-function, start a thread where you execute the actual functionality.
http://doc.qt.digia.com/stable/thread-basics.html
Qt also has asynchronous functions:
http://doc.qt.digia.com/stable/qtconcurrentrun.html
Basically what Gjordis is saying you have to run the custom class where the QNetworkAccessManager resides asynchronously. You have 2 simple choices :
Either invoke asynchronous the methods of your class using QtConcurrent::run
Either handle this class events in another thread, see this excellent minimal example. The only thing is that the doWork() mentionned is really a doInit() or startWork() depending on the situation.
With both of these cases it is primordial to interact with the class only using signals and slots , otherwise you may encounter races conditions. Which means the "consumer" UI thread should not use getters\setters. Locking is not a good option, as the UI thread will require to perform an eventually blocking operation to get his data.
You should emit different signals in sequence from the same Object: a signal for every different object that is interested.
In this way you can decide the order and decide if send message to all or only to some.
Related
I have an ordinary GUI Thread (Main Window) and want to attach a Worker thread to it. The Worker thread will be instantiated, moved to its own thread and then fired away to run on its own independently, running a messaging routine (non-blocking).
This is where the worker is created:
void MainWindow::on_connectButton_clicked()
{
Worker* workwork;
workwork= new Worker();
connect(workwork,SIGNAL(invokeTestResultsUpdate(int,quint8)),
this,SLOT(updateTestResults(int,quint8)),Qt::QueuedConnection);
connect(this,SIGNAL(emitInit()),workwork,SLOT(init()));
workwork->startBC();
}
This is where the Worker starts:
void Worker::startBC()
{
t1553 = new QThread();
this->moveToThread(t1553);
connect(t1553,SIGNAL(started()),this,SLOT(run1553Process()));
t1553->start();
}
I have two problems here, regarding the event queue of the new thread:
The first and minor problem is that, while I can receive the signals from the Worker thread (namely: invokeTestResultsUpdate), I cannot invoke the init method by emitting the emitInit signal from MainWindow. It just doesn't fire unless I call it directly or connect it via Qt::DirectConnection . Why is this happening? Because I have to start the Worker thread's own messaging loop explicitly? Or some other thing I'm not aware of? (I really fail to wrap my head around the concept of Thread/Event Loop/Signal Slot mechanism and the relation between each other even though I try. I welcome any fresh perspective here too.)
The second and more obscure problem is: run1553process method does some heavy work. By heavy work, I mean a very high rate of data. There is a loop running, and I try to receive the data flowing from a device (real-time) as soon as it lands in the buffer, using mostly extern API functions. Then throw the mentioned invokeTestResultsUpdate signal towards the GUI each time it receives a message, updating the message number box. It's nothing more than that.
The thing I'm experiencing is weird; normally the messaging routine is mostly unhindered but when I resize the main window, move it, or hide/show the window, the Worker thread skips many messages. And the resizing action is really slow (not responds very fast). It's really giving me a cancer.
(Note: I have tried subclassing QThread before, it did not mitigate the problem.)
I've been reading all the "Thread Affinity" topics and tried to apply them but it still behaves like it is somehow interrupted by the GUI thread's events at some point. I can understand MainWindow's troubles since there are many messages at the queue to be executed (both the invoked slots and the GUI events). But I cannot see as to why a background thread is affected by the GUI events. I really need to have an extremely robust and unhindered message routine running seperately behind, firing and forgetting the signals and not giving a damn about anything.
I'm really desperate for any help right now, so any bit of information is useful for me. Please do not hesitate to throw ideas.
TL;DR: call QCoreApplication::processEvents(); periodiacally inside run1553process.
Full explanation:
Signals from the main thread are put in a queue and executed once the event loop in the second thread takes control. In your implementation you call run1553Process as soon as the thread starts. the control will not go back to the event loop until the end of that function or QCoreApplication::processEvents is manually invoked so signals will just sit there waiting for the event loop to pick them up.
P.S.
you are leaking both the worker and the thread in the code above
P.P.S.
Data streams from devices normally provide an asynchronous API instead of you having to poll them indefinetly
I finally found the problem.
The crucial mistake was connecting the QThread's built in start() signal to run1553Process() slot. I had thought of this as replacing run() with this method, and expected everything to be fine. But this caused the actual run() method to get blocked, therefore preventing the event loop to start.
As stated in qthread.cpp:
void QThread::run()
{
(void) exec();
}
To fix this, I didn't touch the original start() signal, instead connected another signal to my run1553Process() independently. First started the thread ordinarily, allowed the event loop to start, then fired my other signals. That did it, now my Worker can receive all the messages.
I think now I understand the relation between threads and events better.
By the way, this solution did not take care of the message skipping problem entirely, but I feel that's caused by another factor (like my message reading implementation).
Thanks everyone for the ideas. I hope the solution helps some other poor guy like me.
sorry, I can`t be mor speciic, because I am stuck in a jumble of classes, and several signal/slots.
In my project I use several signal-slots. Now I have the impression that depending on how often I start a routine that emits a signal my slot is run several times.
For the first rum my Slot is run once; In the second run it is run twice.... When I close my program I start again with running it once.
Is there a need to somehow finish/end/delete a signal after it is sent ?
Thank you
Take a look to the Qt::UniqueConnection flag.
You're connecting signals to slots in reaction to events. This causes duplicate connections as the events are repeated. In most cases, this is a bug. Usually you want to set up connections in class constructors, or otherwise when new objects are created and added to your system.
The unique connection will mask the problem, but not solve it - the solution is to move the connect statements to locations where they won't be re-executed.
A a signal stays connected, until either the disconnect() is used, or the sender or receiver is deleted.
So each signal/slot pair has to beconnected only once, and then every time the signal is emitted, the slot gets called.
I have an entertaining problem to solve. I use Qt 5 for one of my projects for reading information on the network. I read modbus devices and stuff, but the real problem comes when the network isn't available.
The interface freezes and I can't interact with it. The network stuff is done in a separate thread or that is what I think. Here is some code example:
class TwidoDevice : public QObject
{
Q_OBJECT
public:
explicit TwidoDevice
........ And some useful code
The use of the (main interface) class in Window.cpp is:
L1Thread = new QThread();
L1Thread->start();
L1TWD = new TwidoDevice(L1TWD_settings,
L1TWD_Name,
PercentRegisters,
TotalsRegisters,
db, 1);
L1TWD->moveToThread(L1Thread);
connect(this, SIGNAL(startReading()), L1TWD, SLOT(startFired()), Qt::DirectConnection);
In this code startFired() start reading the devices on the network.
In some other function in Window.cpp:
emit startReading()
When this code is executed the interface freezes even though I've moved the L1TWD object to QThread.
When I try to debug it using the built-in debugger in QtCreator, I can't seem to understand whether the object has been moved or not and why the interface is frozen during the network call.
Has any one encountered the same problem and what is the way to solve this?
Thank you for spending time reading my question!
This is the main problem:
connect(this, SIGNAL(startReading()), L1TWD, SLOT(startFired()), Qt::DirectConnection);
You are connecting the receiver and sender in different threads with direct connection, which will block the UI. Given that your slot execution gets stuck, this is expected. You have at least two issues here to solve.
Use the default connection which will not block across threads, just inside the same thread. So, you would be writing something like this:
connect(this, SIGNAL(startReading()), L1TWD, SLOT(startFired()));
Secondly, you could make sure that your thread does not get stuck when there is some "network" problem.
For debugging purposes, please print out the current thread when having this kind of threading issues using the following methods:
[static] QThread * QThread::​currentThread()
Returns a pointer to a QThread which manages the currently executing thread.
and this:
[static] Qt::HANDLE QThread::​currentThreadId()
Returns the thread handle of the currently executing thread.
Warning: The handle returned by this function is used for internal purposes and should not be used in any application code.
Warning: On Windows, the returned value is a pseudo-handle for the current thread. It can't be used for numerical comparison. i.e., this function returns the DWORD (Windows-Thread ID) returned by the Win32 function getCurrentThreadId(), not the HANDLE (Windows-Thread HANDLE) returned by the Win32 function getCurrentThread().
You are using a Qt::DirectConnection for your connection, which means the slot is called immediately, i.e on the same thread as the signal was fired. You can have a look at the documentation for ConnectionType. What you want to use is probably Qt::QueuedConnection, which executes the slot in the thread of the receiving object.
The best way though, as lpapp pointet out, is to let Qt decide what is best, and simply use Qt::AutoConnection, which is the default. It will use a QueuedConnection if signaling and receiving threads are different, and DirectConnection otherwise.
This is my scenario: I have a dll (with Qt in the back-end, and with no event loop started). I am able to perform the signal-slot communication with-in this dll (there is a only one thread). I would like to use the facilities of QFileSystemWatcher in this dll. But it looks like, QFileSystemWatcher starts its own thread, and it is not able to communicate to my main thread since there is no event process.
So, basically I need a way to start the event processing without being blocked !
So, basically I need a way to start the event processing without being blocked !
So, basically you want to use QEventLoop features without using the QEventLoop based on the comment discussion. The QEventLoop has to be "blocking", inherently, in order to actually have an event loop.
You could always create a "blocking" thread with the event loop inside, but then your signal-slot management might be tied to that particular thread.
This is not the usual way of using an event loop, but depending on your concrete scenario, it might be sufficient in this special case.
The title is very cryptic, so here goes!
I am writing a client that behaves in a very synchronous manner. Due to the design of the protocol and the server, everything has to happen sequentially (send request, wait for reply, service reply etc.), so I am using blocking sockets. Here is where Qt comes in.
In my application I have a GUI thread, a command processing thread and a scripting engine thread. I create the QTcpSocket in the command processing thread, as part of my Client class. The Client class has various methods that boil down to writing to the socket, reading back a specific number of bytes, and returning a result.
The problem comes when I try to directly call Client methods from the scripting engine thread. The Qt sockets randomly time out and when using a debug build of Qt, I get these warnings:
QSocketNotifier: socket notifiers cannot be enabled from another thread
QSocketNotifier: socket notifiers cannot be disabled from another thread
Anytime I call these methods from the command processing thread (where Client was created), I do not get these problems.
To simply phrase the situation:
Calling blocking functions of QAbstractSocket, like waitForReadyRead(), from a thread other than the one where the socket was created (dynamically allocated), causes random behaviour and debug asserts/warnings.
Anyone else experienced this? Ways around it?
Thanks in advance.
I'm assuming that you're using QThread for the threading operations. If so, you can either a) use queued signal-slot connections; or b) explicitly use the QThread's event loop by creating a custom event type, posting that event in your scripting engine, and then having the client class handle those events.
example for a)
class ClientThread : public QThread
{
..stuff..
public slots:
waitForReadyRead();
};
class ScriptEngineThread : public QThread
{
..other stuff..
signals:
void requestWaitForReadyRead();
};
// In the ScriptEngineThread implementation...
ScriptEngineThread::setupClient()
{
connect(this, SIGNAL(requestWaitForReadyRead()),
client_, SLOT(waitForReadyRead()),
Qt::QueuedConnection);
}
Then, whenever you want to do the socket operations, just emit ScriptEngineThread::requestWaitForReadyRead();. The major difficulty is, I assume, you need the scripting thread to wait for some socket operation to be done. In this case you'll need to fire signals back and forth between the threads, causing some circular dependancy.
For alternative b, it would require a little more coding work, but you could:
Create your own subclasses of QEvent
Create a class to operate as a middleman, posting and handling each of your QEvents and emitting signals to communicate with the threads - each thread can have an instance of this
Connect the client and script engine to the event signals it cares about.