Emitting signal from callback - qt

I am using RtMidi library to handle midi message in my Qt application and I am facing problem with slot trigger:
My PhMidiInput object is emiting signal from the RtMidi callback upon specific midi message but the slots are not always triggered.
Here is a part of the PhMidiInput class:
class PhMidiInput : QObject
{
Q_OBJECT
public:
void PhMidiInput() {}
signals:
void quarterFrame(unsigned char data);
private:
static void callback(double, std::vector< unsigned char > *message, void *userData ) {
PhMidiInput *midiInput = (PhMidiInput*)userData;
if(midiInput)
midiInput->onMessage(message);
}
void onMessage(std::vector<unsigned char> *message) {
...
emit quarterFrame(data);
...
}
}
Connecting to a lambda functor works:
PhMidiInput midiIn;
int quarterFrameCount;
connect(&midiIn, &PhMidiInput::quarterFrame, [&](unsigned char data) {
quarterFrameCount++;
});
Connecting to my application window works to:
// MyWindow inherits from QMainWindow
connect(_midiIn, &PhMidiInput::quarterFrame, this, &MyWindow::onQuarterFrame);
When trying to connect to a custom class (MidiTest) inheriting from QObject it does'nt trigger:
connect(_midiIn, &PhMidiInput::quarterFrame, this, &MidiTest::onQuarterFrame);
I was wondering if there was something around QObject::moveToThread() but since I don't create the thread myself (the signal is sent from a callback) I don't know if I need to use it or not.

It is as simple as calling emit obj->quarterFrame(data); from the callback. If the connection type is default then this will be perfectly thread safe.
Though you should create a QByteArray from data to pass around as data will likely not be valid by the time the slots get called.
void callback(..., void* user){
//user is the standard void* in most callbacks passed as reinterpret_cast<void*>(this)
unsigned char* data = ...;
QByteArray bytes(data);
emit reinterpret_cast<PhMidiInput>(user)->quarterFrame(bytes);//calling the signal which will behave as you'd expect
}

In the last connect() call you pass this and MidiTest::onQuarterFrame as the receiver object and method. I bet this is not an instance of MidiTest, is it?
The problem here is that you're passing SLOT method from MidiTest, while the receiver object is this, which is not instance of MidiTest. Change receiver from this to some instance of MidiTest.
I'm surprised this code doesn't crash your application when running.

Related

Qt: How to avoid deadlock when multiple queued signals invoke same slot

In following code I meet deadlock in someOperation:
class A : public QObject {
Q_OBJECT
public:
explicit A(QObject* parent) : QObject(parent), data(0) {}
public slots:
void slot1() {
someOperation();
}
void slot2() {
someOperation();
}
void slot3() {
someOperation();
}
private:
void someOperation() {
QMutexLocker lk(&mutex);
data++;
QMessageBox::warning(NULL, "warning", "warning");
data--;
assert(data == 0);
}
int data;
QMutex mutex; //protect data
};
class Worker: public QThread {
Q_OBJECT
public:
explicit Worker(QObject* parent) : QThread(parent) {}
protected:
virtual void run() {
// some complicated data processing
emit signal1();
// other complicated data processing
emit signal2();
// much complicated data processing
emit signal3();
qDebug() << "end run";
}
signals:
void signal1();
void signal2();
void signal3();
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
A* a = new A(&app);
Worker* w = new Worker(a);
QObject::connect(w, SIGNAL(signal1()), a, SLOT(slot1()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal2()), a, SLOT(slot2()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal3()), a, SLOT(slot3()), Qt::QueuedConnection);
w->start();
return app.exec();
}
There is a thread that will emit three signals, all of them queued connected to an instance of class A, and all class A' slots will call to someOperation, and someOperation is protected by mutex and it will popup a message box.
Qt::QueuedConnection 2 The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.
It seems slot2 is invoked when slot1's message box still doing modal, in main thread, but at that time slot1 has lock mutex, so deadlock.
How to change the code to avoid deadlock?
Update:(Jan.17, 2019)
What I want archive is that: slot2 not be execute before slot1 finished.
What should be kept are:
worker is a background thread to process data, cost long time; so, whatever, the three signals will emit from other thread.
worker should not blocked by emitting signals.
slots should execute in main thread, because they will update GUI.
someOperation is not reentrant.
The requirement that "someOperation is not reentrant" is an odd one. What should happen if reentrancy is attempted? Given that someOperation can only be called from the main thread I can only see two options...
Block completely with mutex/barrier etc. as you have tried.
Block based on a recursion level counter and spin the event loop until that counter decrements to zero.
1) Will block the thread's event loop completely preventing the current message dialog from functioning correctly.
2) Will allow all message dialogs simultaneously rather then serialising them.
Rather than trying to make someOperation non-reentrant I think you need to make sure you use in a way that won't result in reentrancy.
One option might be to make use of a separate QObject derived class instance on its own QThread. Consider the following...
class signal_serialiser: public QObject {
Q_OBJECT;
signals:
void signal1();
void signal2();
void signal3();
};
If an instance of signal_serialiser is moved to its own thread it can act as a queue to buffer and forward the various signals if suitable connection types are used. In your code you currently have...
QObject::connect(w, SIGNAL(signal1()), a, SLOT(slot1()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal2()), a, SLOT(slot2()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal3()), a, SLOT(slot3()), Qt::QueuedConnection);
Change that to...
signal_serialiser signal_serialiser;
QObject::connect(w, SIGNAL(signal1()), &signal_serialiser, SIGNAL(signal1()));
QObject::connect(w, SIGNAL(signal2()), &signal_serialiser, SIGNAL(signal2()));
QObject::connect(w, SIGNAL(signal3()), &signal_serialiser, SIGNAL(signal3()));
/*
* Note the use of Qt::BlockingQueuedConnection for the
* signal_serialiser --> A connections.
*/
QObject::connect(&signal_serialiser, SIGNAL(signal1()), a, SLOT(slot1()), Qt::BlockingQueuedConnection);
QObject::connect(&signal_serialiser, SIGNAL(signal2()), a, SLOT(slot2()), Qt::BlockingQueuedConnection);
QObject::connect(&signal_serialiser, SIGNAL(signal3()), a, SLOT(slot3()), Qt::BlockingQueuedConnection);
QThread signal_serialiser_thread;
signal_serialiser.moveToThread(&signal_serialiser_thread);
signal_serialiser_thread.start();
I've only done basic testing but it appears to give the desired behaviour.
That's because your function void someOperation() is not reentrant.
The static functions of QMessageBox span their own event loop, which calls QCoreApplication::processEvents() repeatedly:
Execution of the first invocation of someOperation() gets stuck at QMessageBox::warning(...).
In there, exec() calls processEvents(), 3. which sees the second signal
and invokes someOperation() again
where trying to re-lock mutex fails.
How to resolve this depends on what you want to achieve...
About your general approach to QThread: You're doing it wrong.
(That link gives a good start into the topic, but not a complete solution.)
You create and start a background thread. But that thread will only emit the three signals and then finish.
The slots will be called inside the main (GUI) event loop, because that's the thread affinity of your A *a.
To make the slots be executed in the background, you need to:
create your A instance without a parent: A *a = new A();
create your Worker instance with the app as parent: Worker *w = new Worker(&app); (or with nothing, at least not with a)
change the thread affinity of your A instance: a->moveToThread(Worker);
don't override Worker::run(), or if you really want to (see point 5), call the base implementation: QThread::run();
emit the signals from main (you can emit them from run(), but that's not necessary).

Qt: How to know if slot was called by signal-slot mechanism by calling the signal like a function

Inside a slot I check the QObject::sender() but now I want to call this slot directly like a function.
Can I know how this slot was called inside of the slot? Either by signal-slot mechanism or simply by calling the slot like a function?
You can check the sender() in both cases. In case of the slot being called via a signal/slot mechanism the sender will return a pointer while when called as a method it will return null pointer.
Simple example:
class Test : public QObject
{
Q_OBJECT
signals:
void signal();
public slots:
void slot() { qDebug() << sender(); }
};
And the use:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Test test;
Test test2;
QObject::connect(&test, &Test::signal, &test2, &Test::slot);
test.signal(); //slot is caled by signal
test2.slot(); //slot is called as method directly
return a.exec();
}
And the output:
Test(0xa8e8aff5b0)
QObject(0x0)
Add a default parameter to your slot:
public slots:
void slot(bool calledBySignal = true);
Set the parameter to false when calling the slot directly:
void MyClass::method()
{
[...]
slot(false);
[...]
}
Leave the connect() calls as they are; don't add a bool parameter to the signals, nor change SLOT(slot()) to SLOT(slot(bool)).
Disadvantage: It's easy to forget setting the parameter.
If your slot doesn't need to be public, because connect()ing to it is handled from inside the class only, you should make it private and add a wrapper method that's to be called instead, but still you'll need some discipline when calling it from inside the class. Johannes' suggestion would solve these issues.
Another idea to distinguish between direct function call vs. Signal/Slot-invocation:
Use the method int QObject::senderSignalIndex() const and check for -1
if(QObject::senderSignalIndex() == -1){
//called directly as a function
} else {
// invoked via Signal/SLot mechanism
}
Returns the meta-method index of the signal that called the currently executing slot, which is a member of the class returned by sender(). If called outside of a slot activated by a signal, -1 is returned.
see Qt 4.8 documentation
This looks like a clean way to distinguish and there is no chance of getting into trouble with a null-pointer in contrast to using QObject * QObject::sender() const.
Regards,
Felix

Avoid having to qRegisterMetaType (pointer vs reference), concern about const

Given the signal:
void dbConnected(const QSqlDatabase &db);
I learned (from Qt Communication betwen threads, app design) how to avoid having to use
qRegisterMetaType<QSqlDatabase>("QSqlDatabase");
Just changing the signal to this form:
void dbConnected(QSqlDatabase *db);
And, in the slot side I'll use something like this:
void onDBConnected(QSqlDatabase * const db);
I'm concerned with the usage of db (as in the beginning I've made the reference const), so I make it const here (in the slot side). I've tried to do the same in the signal side with
void dbConnected(QSqlDatabase * const db);
But doing so I have the runtime error (mentioned in Qt Communication betwen threads, app design) back. So I tried another form, which seems to do the job:
void dbConnected(QSqlDatabase *db) const;
Am I in the right direction?
Am I in the right direction?
Maybe. First, make sure that you know that you cannot pass the database to an object living in another thread. That was one of the major mistakes you did in the code in the other question. Don't do that anymore.
If you're passing an object via reference, it must be copyable. A QSqlDatabase is copyable after you open it. So you're OK here, too.
But you might not need to pass the database reference at all. QSqlDatabase assigns a name to each connection. Instead of passing the databases by value or by pointer, you can pass their connection names instead, and use QSqlDatabase::database to get a database object representing a given connection.
For example:
class Opener : public QObject {
Q_OBJECT
QSqlDatabase m_db;
public:
Q_SIGNAL void dbOpened(const QString &);
void open() {
m_db.addDatabase("FOO", "cats");
...
if (m_db.open()) emit dbOpened(m_db.connectionName());
}
};
class DbUser : public QObject {
Q_OBJECT
QSqlDatabase m_db;
public:
Q_SLOT void onDbOpened(const QString & conn) {
m_db = QSqlDatabase::database(conn);
}
...
};
As you can see, the dbOpened signal emits not a database, but a database connection name, and then the various objects that wish to use that connection can retrieve the database object (handle) by name.

Is there a guarantee that no signals are delivered from a different thread after QObject::disconnect()?

I am not thinking of the problem that queued signals are still delivered in the receiving thread after disconnect(), instead:
Consider the case that a Sender object is generating signals in thread 1 and there is a Receiver object in thread 2 which has a slot that is connected to Sender's signal via a Qt::DirectConnection.
Now, in Receiver::~Receiver(), I need to make sure that no signals are still delivered while the object is already (maybe partially) destructed. Because the connection is direct, the slot could be invoked in thread 1 at any time and could in particular happen between destruction of Receiver's specific attributes and destruction of the base QObject which will also disconnect signals. So, my question boils down to:
Is it enough to disconnect Sender and Receiver objects in thread 2 before destruction of the Receiver object, or do I need to make sure that no signals are emitted in thread 1 during the disconnect() call?
I am thinking of the case where thread 1 is in the middle of emitting the signal, e.g. right at the top of executing the receiving slot and right at that moment, in thread 2, the disconnect() call is done. If disconnect() waits (via a mutex) for thread 1 to finish delivering the signal before doing the disconnect and blocking further signal deliveries, everything would be fine but I am not sure that's the case.
Yes disconnect() and connect() are using mutexes for protection.
These are the first lines of the disconnect() function:
bool QMetaObjectPrivate::disconnect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index,
DisconnectType disconnectType)
{
if (!sender)
return false;
QObject *s = const_cast<QObject *>(sender);
QMutex *senderMutex = signalSlotLock(sender);
QMutex *receiverMutex = receiver ? signalSlotLock(receiver) : 0;
QOrderedMutexLocker locker(senderMutex, receiverMutex);
And here are the first lines of the connect() function:
bool QMetaObjectPrivate::connect(const QObject *sender, int signal_index,
const QObject *receiver, int method_index, int type, int *types)
{
QObject *s = const_cast<QObject *>(sender);
QObject *r = const_cast<QObject *>(receiver);
QOrderedMutexLocker locker(signalSlotLock(sender),
signalSlotLock(receiver));
If you check the QObject documentation you can see that :
Note: All functions in this class are reentrant, but connect(),
connect(), disconnect(), and disconnect() are also thread-safe.
EDIT
When a signal is emitted the QMetaObject::activate function is called which locks the sender's object mutex:
void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index,
void **argv)
{
...
QMutexLocker locker(signalSlotLock(sender));

How to delete a QProcess instance correctly?

I have a class looking like this:
class FakeRunner : public QObject
{
Q_OBJECT
private:
QProcess* proc;
public:
FakeRunner();
int run()
{
if (proc)
return -1;
proc = new QProcess();
QStringList args;
QString programName = "fake.exe";
connect(comp, SIGNAL(started()), this, SLOT(procStarted()));
connect(comp, SIGNAL(error(QProcess::ProcessError)), this,
SLOT(procError(QProcess::ProcessError)));
connect(comp, SIGNAL(finished(int, QProcess::ExitStatus)), this,
SLOT(procFinished(int, QProcess::ExitStatus)));
proc->start(programName, args);
return 0;
};
private slots:
void procStarted() {};
void procFinished(int, QProcess::ExitStatus) {};
void procError(QProcess::ProcessError);
}
Since "fake.exe" does not exist on my system, proc emits the error() signal. If I handle it like following, my program crashes:
void FakeRunner::procError(QProcess::ProcessError rc)
{
delete proc;
proc = 0;
}
It works well, though, if I don't delete the pointer. So, the question is how (and when) should I delete the pointer to QProcess? I believe I have to delete it to avoid a memory leak. FakeRunner::run() can be invoked many times, so the leak, if there is one, will grow.
Thanks!
You can't delete QObject instance inside slot which is connected to a signal in this instance using normal delete operator. This is due to the fact that if signal and slot connected using direct connection then the slot actually called from the signal implementation made by moc. This is like attempt to delete this; from inside the member of a class. There is a solution QObject::deleteLater(). Object will be deleted by Qt event loop inside events processing function. So you need to call proc->deleteLater() in your case.
And you don't need to disconnect signal from slot since Qt do it automatically when QObject is deleted.

Resources