I have implemented a class in Qt to receive char inputs and filter them and return meaningful char arrays to me, and also this is done in a different thread than the original thread.
Here's the header file:
class WorkerThread : public QObject
{
Q_OBJECT
QThread highspeedthread;
int bufferCounter=0;
public:
char buffer[260];
WorkerThread();
public slots:
void doWork(char parameter); // This is the function to do the filtering
signals:
void resultReady(char*); // Signal for when the result is made, It gets connected to HighspeedProcessor::handleresult
};
class HighspeedProcessor : public QObject
{
Q_OBJECT
QThread highspeedthread;
public:
HighspeedProcessor();
signals:
void process(char); // This is the function from which the cycle starts
public slots:
void handleResult(char*); // This gets the results back
};
And here's the definitions:
void WorkerThread::doWork(char parameter)
{
buffer[bufferCounter] = parameter;
// Filters the input and fills the buffer
// Code omitted for easement
// ...
qDebug()<<"Before: "<<buffer;
emit resultReady(buffer); // Pass the buffer to HighspeedProcessor::handleResult
}
HighspeedProcessor::HighspeedProcessor() {
WorkerThread *worker = new WorkerThread;
worker->moveToThread(&highspeedthread);
connect(this, SIGNAL(process(char)), worker, SLOT(doWork(char)));
connect(worker,SIGNAL(resultReady(char*)), this,SLOT(handleResult(char*)));
highspeedthread.start();
}
void HighspeedProcessor::handleResult(char *parameter)
{
qDebug()<<"After: "<<parameter;
}
The WorkerThread is doing its work just fine and filters results flawlessly, but problem is that when the result is passed to the HighspeedProcessor class, the char array gets mixed up. The result is as shown below:
Before: $CMDgFlushing FIFO
After: $CMDgFlushing FIFO�:�"��ά!���j�D��#�/�]%�i�����Rր�������y�r��<�F��!]�uh����q�=S�ߠ�"�M�d
Before: $CMDgFlushing FIFO
After: $CMDgFlushing FIFO
Before: $CMDgFlushing FIFO
After: $CMDgFlushing ��o���kj���q�9 ����^ou����
And by the way this is not happening so frequently, meaning only once out of almost 100 times it gets mixed up and other times it's ok. Also the rate of input data is almost 1Mb/s. Am I doing something wrong?
EDIT: This was already happening before I used qDebug in my code. So, it's not the result of using qDebug.
Your mistakes:
Your are using the buffer in two different threads, but are passing
only a pointer to it, it is pointless.
Don't protect a reading/writing to the buffer
You don't need even to use any thread-safe exchange buffer, you simply can pass a QByteArray as a parameter between threads through signals-slots.
For example:
QByteArray buffer;
//...
signals:
void resultReady(QByteArray);
//...
void WorkerThread::doWork(char parameter)
{
buffer[bufferCounter] = parameter;
//...
emit resultReady(buffer);
}
void HighspeedProcessor::handleResult(QByteArray parameter)
{
qDebug() << "After: "<< parameter;
}
Changing my char* variables to QByteArray solved my problem. Somehow there was some conflict happening between the two threads that used the same pointer for buffer.
Related
I am prity new on Qt an got some issues with QSharedPointer passing around within signals. I am working with two threads (UI and a worker). The worker sends signals to the UI using signals that contain QSharedPointer of a custom QObject:
class MyObject : QObject {...}
class Window : public QWidget {
Q_OBJECT
public slots:
void onFound(QSharedPointer<MyObject>);
}
class Worker : public QObject {
Q_OBJECT
public signals:
void found(QSharedPointer<MyObject>);
}
I connect the workers found with the windows onFound with Qt::QueuedConnection because they live in different Threads and the communication therefore has to be asynchronous.
Now I observe the folowing behavior, when I pass a the last QSharedPointer refering to my object:
The signal moc casts the reference to my pointer to void* and arcives it.
The function returns resulting in the shared pointer and the corresponding object to be destroyed.
That's not what I expected - though it's reasonable. Are QSharedPointer in general designed to be passed through signals that way? And if so, is there a mecanism to keep a reference while it is queued?
I considered the folowing solutions, but I'm not totally fine with neither of them:
Keep a reference somewhere that keeps reference while it is queued. But where is a reasonable place to do that and when should I let it go.
Make the connection Qt::DirectConnection but then I am still have to switch the thread somehow (same situation as before)
Introduce a new signal/slot with std::function parameter for passing a lambda function to be executed in the target thread and capturing a copy of my shared pointer. (This is my current solution but it's not perty elegant, isn't it?)
Do you have any other suggestions or ideas?
The signal return does not destroy the corresponding object. The QMetaObject::activate call copies the shared pointer. Here's the implementation of send signal:
// SIGNAL 0
void IO::send(const QSharedPointer<Unique> & _t1)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
You're probably experiencing a race: by the time the thread where the signal was emitted resumes execution, the destination thread has already received the object. Thus it appears in the emitting thread that the object is gone - because, by that time, it is. Yet the target object receives the instance just fine. It works fine.
The example below illustrates that it works in both single- and multi-threaded cases, and then reproduces your problem by ensuring that the race is always won by the destination thread:
// https://github.com/KubaO/stackoverflown/tree/master/questions/shared-pointer-queued-49133331
#include <QtCore>
class Unique : public QObject {
Q_OBJECT
int const m_id = []{
static QAtomicInteger<int> ctr;
return ctr.fetchAndAddOrdered(1);
}();
public:
int id() const { return m_id; }
};
class IO : public QObject {
Q_OBJECT
int m_lastId = -1;
public:
Q_SIGNAL void send(const QSharedPointer<Unique> &);
Q_SLOT void receive(const QSharedPointer<Unique> & u) {
m_lastId = u->id();
}
int lastId() const { return m_lastId; }
};
int main(int argc, char ** argv) {
Q_ASSERT(QT_VERSION >= QT_VERSION_CHECK(5,9,0));
QCoreApplication app{argc, argv};
IO src, dst;
QObject::connect(&src, &IO::send, &dst, &IO::receive, Qt::QueuedConnection);
QSharedPointer<Unique> u;
QWeakPointer<Unique> alive;
int id = -1;
// Single-threaded case
alive = (u.reset(new Unique), u);
id = u->id();
Q_ASSERT(dst.lastId() != id); // the destination hasn't seen the object yet
emit src.send(u);
u.reset();
Q_ASSERT(!u); // we gave up ownership of the object
Q_ASSERT(dst.lastId() != id); // the destination mustn't seen the object yet
Q_ASSERT(alive); // the object must be still alive
app.processEvents();
Q_ASSERT(dst.lastId() == id); // the destination must have seen the object now
Q_ASSERT(!alive); // the object should have been destroyed by now
// Multi-threaded setup
struct Thread : QThread { ~Thread() { quit(); wait(); } } worker;
worker.start();
dst.moveToThread(&worker);
QSemaphore s_src, s_dst;
// This thread wins the race
alive = (u.reset(new Unique), u);
id = u->id();
Q_ASSERT(dst.lastId() != id);
QTimer::singleShot(0, &dst, [&]{ s_src.release(); s_dst.acquire(); });
// stop the thread
s_src.acquire(); // wait for thread to be stopped
emit src.send(u);
QTimer::singleShot(0, &dst, [&]{ s_src.release(); });
// resume the main thread when done
u.reset();
Q_ASSERT(!u);
Q_ASSERT(alive); // we won the race: the object must be still alive
s_dst.release(); // get the thread running
s_src.acquire(); // wait for the thread to be done
Q_ASSERT(dst.lastId() == id);
Q_ASSERT(!alive);
// The other thread wins the race
alive = (u.reset(new Unique), u);
id = u->id();
Q_ASSERT(dst.lastId() != id);
emit src.send(u);
QTimer::singleShot(0, &dst, [&]{ s_src.release(); });
// resume the main thread when done
u.reset();
s_src.acquire(); // wait for worker thread to be done
Q_ASSERT(!u);
Q_ASSERT(!alive); // we lost the race: the object must be gone
Q_ASSERT(dst.lastId() == id); // yet the destination has received it!
// Ensure the rendezvous logic didn't mess up
Q_ASSERT(id == 2);
Q_ASSERT(!s_src.available());
Q_ASSERT(!s_dst.available());
}
#include "main.moc"
I'm trying to understand and use RAII and wanted opinions on this implementation:
I want the RAII PauseProcessRAII to emit a signal and another one in the destructor. Example:
// Header
public:
PauseProcessRAII(QObject *parent = 0);
void Execute();
~PauseProcessRAII();
signals:
void PauseProcess(bool pause_process);
// Source
PauseProcessRAII::~PauseProcessRAII()
{
emit PauseProcess(false);
}
void PauseProcessRAII::Execute()
{
emit PauseProcess(true);
}
// MainWindow code
void MainWindow::OnPauseProcessRAII(bool pause_process)
{
qDebug() << "pause_process: " << pause_process;
}
void MainWindow::OnButtonSaveClicked()
{
PauseProcessRAII pauseProcessRAII(this);
connect(&pauseProcessRAII, &PauseProcessRAII::PauseProcess, this, &MainWindow::OnPauseProcess);
pauseProcessRAII.Execute();
// ... Some code runs
// ... pauseRAII desctructor is called
}
When I run the code both emits are firing as expected. My question is this a good solution? At first I though the emit call in PauseProcessRAII destructor wouldn't have worked because it may have destroyed the signal and slot connection. Of course that would mean I would have to add the connect to every function that I use it on.
The whole idea is fundamentally broken if your premise is that the code indicated by "Some code runs" runs long enough to block the GUI. If so: don't do that. The only code that is supposed to ever execute in the GUI thread is short, run-to-completion code that doesn't take long enough for the user to notice.
If the time taken by "Some code runs" is very short - on the order of single milliseconds at most - then you can certainly use such a construct. The term RAII doesn't apply here, as you're dealing with some sort of a scope guard.
If you wish, you can forgo the execute method and perform the connection in the constructor:
// https://github.com/KubaO/stackoverflown/tree/master/questions/scopeguard-signal-34910879
// main.cpp
#include <QtCore>
class ScopeSignaller : public QObject {
Q_OBJECT
public:
Q_SIGNAL void inScope(bool);
template <typename F>
ScopeSignaller(QObject * target, F && slot, QObject * parent = 0) : QObject(parent) {
connect(this, &ScopeSignaller::inScope, target, std::forward<F>(slot));
inScope(true);
}
~ScopeSignaller() {
inScope(false);
}
};
int main(int argc, char ** argv) {
QCoreApplication app{argc, argv};
ScopeSignaller s(&app, +[](bool b){ qDebug() << "signalled" << b; });
}
#include "main.moc"
I'm having some issues with Qt threading to allow the threaded part to update the GUI of my program. Seems like it's a known "problem" with Qt, so I found multiple tutorials, but I don't understand why my example here is not working.
I inherited from QThread as follow:
class CaptureThread: public QThread {
Q_OBJECT
public:
CaptureThread(const QObject *handler, QPushButton *start) {
CaptureThread::connect(start, SIGNAL(clicked()), this, SLOT(capture_loop()));
CaptureThread::connect(this, SIGNAL(sendPacket(Packet*)),
this, SLOT(receivePacket(Packet*)));
}
signals:
void sendPacket(Packet*);
public slots:
void capture_loop() {
Packet *packet;
while (my_condition) {
packet = Somewhere::getPacket();
//getPacket is define somewhere and is working fine
emit(sendPacket(packet));
std::cout << "Sending packet!" << std::endl;
}
}
};
And here is the CaptureHandler:
class CaptureHandler: public QWidget {
Q_OBJECT
public:
CaptureHandler() {
start = new QPushButton("Capture", this);
thread = new CaptureThread(this, start);
thread->start();
}
public slots:
void receivePacket(Packet *packet) {
std::cout << "Packet received!" << std::endl;
/*
Here playing with layout etc...
*/
}
private:
QPushButton *start;
CaptureThread *thread;
};
I think the signals and slots are ok, because it displays on the terminal
Sending packet!
Packet received!
Sending packet!
Packet received!
Sending packet!
Packet received!
But in the receivePacket slot, i'm trying to modify my GUI, and it does not work. The GUI just freeze, and all I can do is CTRL+C on terminal.
So i think my capture_loop, which is an infinite loop for the moment, is blocking the program, which means my thread has not started.
But I called thread->start().
I even tried to start the thread in CaptureThread constructor, by calling this->start(), but the result is the same.
Any idea?
Your using QThread wrong. By just creating the thread, it will not execute on the thread. you will need to do it inside the QThread::run function (by overriding it), since thats the only one that will run on the new thread. Please notice, that as soon as you return from this function, the thread will exit.
If you want to use your own loop inside the QThread::run function (instead using Qts default event loop), the thread won't be able to receive signals inside the run-function!
Here an example on how to use QThread:
class CaptureThread: public QThread {
Q_OBJECT
public:
CaptureThread(const QObject *handler, QPushButton *start) {
//calling "start" will automatically run the `run` function on the new thread
CaptureThread::connect(start, SIGNAL(clicked()), this, SLOT(start()));
//use queued connection, this way the slot will be executed on the handlers thread
CaptureThread::connect(this, SIGNAL(sendPacket(Packet*)),
handler, SLOT(receivePacket(Packet*)), Qt::QueuedConnection);
}
signals:
void sendPacket(Packet*);
protected:
void run() {
Packet *packet;
while (my_condition) {
packet = Somewhere::getPacket();
//getPacket is define somewhere and is working fine
emit sendPacket(packet) ;//emit is not a function
qDebug() << "Sending packet!";//you can use qDebug
}
}
};
I have the next classes: FoxCom and FoxComCircle. In FoxCom I have the next code:
...
public slots:
void bytesWrite(QByteArray bytes, qint32 requestedTimeout = -1);
...
FoxComCircle * circle;
...
void FoxCom::bytesWrite(QByteArray bytes, qint32 requestedTimeout)
{
QMetaObject::invokeMethod(circle,
//SLOT(bytesToWrite(QByteArray,qint32)),
"bytesToWrite",
Qt::QueuedConnection,
Q_ARG(QByteArray, bytes),
Q_ARG(qint32, requestedTimeout));
}
And in FoxComCircle:
...
public slots:
void bytesToWrite(QByteArray bytes, qint32 requestedTimeout);
...
void FoxComCircle::bytesToWrite(QByteArray bytes, qint32 requestedTimeout)
{
//some stinky code here
}
And there is the next behaviour: when I comment "bytesToWrite", and use SLOT(bytesToWrite(QByteArray,qint32)), I have the next message in the output console when FoxCom::bytesWrite is called:
QMetaObject::invokeMethod: No such method FoxComCircle::1bytesToWrite(QByteArray
,qint32)(QByteArray,qint32)
But when I use the const char * name directly (as shown in the code above) it works.
Am I doing something wrong?
P.S. FoxCom and FoxComCircle are in different threads.
Thanks in advance.
According to QMetaObject::invokeMethod description in Qt documentation:
Invokes the member (a signal or a slot name) on the object obj...
Thus, you have to provide the name of the slot, and not the complete signature. This is consistent, because you provide slot's arguments as the following arguments of invokeMethod function.
Boost.Signals allows various strategies of using the return values of slots to form the return value of the signal. E.g. adding them, forming a vector out of them, or returning the last one.
The common wisdom (expressed in the Qt documentation [EDIT: as well as some answers to this question ]) is that no such thing is possible with Qt signals.
However, when I run the moc on the following class definition:
class Object : public QObject {
Q_OBJECT
public:
explicit Object( QObject * parent=0 )
: QObject( parent ) {}
public Q_SLOTS:
void voidSlot();
int intSlot();
Q_SIGNALS:
void voidSignal();
int intSignal();
};
Not only doesn't moc complain about the signal with the non-void return type, it seems to actively implement it in such a way as to allow a return value to pass:
// SIGNAL 1
int Object::intSignal()
{
int _t0;
void *_a[] = { const_cast<void*>(reinterpret_cast<const void*>(&_t0)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
return _t0;
}
So: according to the docs, this thing isn't possible. Then what is moc doing here?
Slots can have return values, so can we connect a slot with a return value to a signal with a return value now? May that be possible, after all? If so, is it useful?
EDIT: I'm not asking for workarounds, so please don't provide any.
EDIT: It obviously isn't useful in Qt::QueuedConnection mode (neither is the QPrintPreviewWidget API, though, and still it exists and is useful). But what about Qt::DirectConnection and Qt::BlockingQueuedConnection (or Qt::AutoConnection, when it resolves to Qt::DirectConnection).
OK. So, I did a little more investigating. Seems this is possible. I was able to emit a signal, and receive value from the slot the signal was connected to. But, the problem was that it only returned the last return value from the multiple connected slots:
Here's a simple class definition (main.cpp):
#include <QObject>
#include <QDebug>
class TestClass : public QObject
{
Q_OBJECT
public:
TestClass();
Q_SIGNALS:
QString testSignal();
public Q_SLOTS:
QString testSlot1() {
return QLatin1String("testSlot1");
}
QString testSlot2() {
return QLatin1String("testSlot2");
}
};
TestClass::TestClass() {
connect(this, SIGNAL(testSignal()), this, SLOT(testSlot1()));
connect(this, SIGNAL(testSignal()), this, SLOT(testSlot2()));
QString a = emit testSignal();
qDebug() << a;
}
int main() {
TestClass a;
}
#include "main.moc"
When main runs, it constructs one of the test classes. The constructor wires up two slots to the testSignal signal, and then emits the signal. It captures the return value from the slot(s) invoked.
Unfortunately, you only get the last return value. If you evaluate the code above, you'll get: "testSlot2", the last return value from the connected slots of the signal.
Here's why. Qt Signals are a syntax sugared interface to the signaling pattern. Slots are the recipients of a signal. In a direct connected signal-slot relationship, you could think of it similar to (pseudo-code):
foreach slot in connectedSlotsForSignal(signal):
value = invoke slot with parameters from signal
return value
Obviously the moc does a little more to help in this process (rudimentary type checking, etc), but this helps paint the picture.
No, they can't.
Boost::signals are quite different from those in Qt. The former provide an advanced callback mechanism, whereas the latter implement the signaling idiom. In the context of multithreading, Qt's (cross-threaded) signals depend on message queues, so they are called asynchronously at some (unknown to the emitter's thread) point in time.
Qt's qt_metacall function returns an integer status code. Because of this, I believe this makes an actual return value impossible (unless you fudge around with the meta object system and moc files after precompilation).
You do, however, have normal function parameters at your disposal. It should be possible to modify your code in such a way to use "out" parameters that act as your "return".
void ClassObj::method(return_type * return_)
{
...
if(return_) *return_ = ...;
}
// somewhere else in the code...
return_type ret;
emit this->method(&ret);
You may get a return value from Qt signal with the following code:
My example shows how to use a Qt signal to read the text of a QLineEdit.
I'm just extending what #jordan has proposed:
It should be possible to modify your code in such a way to use "out" parameters that act as your "return".
#include <QtCore>
#include <QtGui>
class SignalsRet : public QObject
{
Q_OBJECT
public:
SignalsRet()
{
connect(this, SIGNAL(Get(QString*)), SLOT(GetCurrentThread(QString*)), Qt::DirectConnection);
connect(this, SIGNAL(GetFromAnotherThread(QString*)), SLOT(ReadObject(QString*)), Qt::BlockingQueuedConnection);
edit.setText("This is a test");
}
public slots:
QString call()
{
QString text;
emit Get(&text);
return text;
}
signals:
void Get(QString *value);
void GetFromAnotherThread(QString *value);
private slots:
void GetCurrentThread(QString *value)
{
QThread *thread = QThread::currentThread();
QThread *mainthread = this->thread();
if(thread == mainthread) //Signal called from the same thread that SignalsRet class was living
ReadObject(value);
else //Signal called from another thread
emit GetFromAnotherThread(value);
}
void ReadObject(QString *value)
{
QString text = edit.text();
*value = text;
}
private:
QLineEdit edit;
};
To use this, just request call();.
You can try to workaround this with following:
All your connected slots must save their results in some place (container) accessible from signaling object
The last connected slot should somehow (select max or last value) process collected values and expose the only one
The emitting object can try to access this result
Just as an idea.