PDA

View Full Version : wait until a signal is processed



mentalmushroom
2nd March 2011, 11:48
Hi all, I am developing a multi-threaded app that emits signals processed in another threads. I need to wait for a signal to be processed. According to the documentation, Qt::BlockingQueuedConnection seems to be right for that case, but the following code doesn't work (connect returns false):


bool con = connect(thread, SIGNAL(mysignal2(MyClass &)), this, SLOT(myslot2(MyClass &)), Qt::BlockingQueuedConnection);

The same problem is also with Qt::QueuedConnection, but if a don't specify the connection type, it works fine, but of course doesn't wait for a signal processing.

So, this code works:


bool con = connect(thread, SIGNAL(mysignal2(MyClass &)), this, SLOT(myslot2(MyClass &)));


I use Q_DECLARE_METATYPE and call qRegisterMetaType before establishing a connection. Please, give me a tip what can be wrong here.

wysota
2nd March 2011, 11:55
Do you get a runtime warning about the connections? How do you use qRegisterMetaType? In general what you have will probably not work because you are using non-const references. Either use const references or if you have to modify the objects being passed through the signal, use pointers. And think twice if you really need a signal to handle this situation. Do you expect more than one receiver to connect to it? Do you expect a situation that no slot is connected to the signal? If answer to any of the two last questions is "no" then you probably shouldn't be using signals at all.

mentalmushroom
2nd March 2011, 12:00
i have MyClass declared as


class MyClass
{
};

Q_DECLARE_METATYPE(MyClass)


and this is how i establish my connections:


MyClass myclass;

qRegisterMetaType<MyClass>();

bool con;
con = connect(thread, SIGNAL(mysignal1(int)), this, SLOT(myslot1(int)), Qt::BlockingQueuedConnection);
con = connect(thread, SIGNAL(mysignal2(MyClass &)), this, SLOT(myslot2(MyClass &)), Qt::BlockingQueuedConnection);


i see the following in the output window:


QObject::connect: Cannot queue arguments of type 'MyClass&'
(Make sure 'MyClass&' is registered using qRegisterMetaType().)
The program '[13916] testsignals.exe: Native' has exited with code 0 (0x0).


maybe the issue is caused by reference?

wysota
2nd March 2011, 12:11
You can try registering the reference as well but in my opinion this doesn't make much sense as the data will get copied anyway.

qRegisterMetaType<MyClass&>("MyClass&");

By the way, are you sure about the affinity of your "thread" object? Can you show us how you declare and use it?

mentalmushroom
2nd March 2011, 12:21
just tried
qRegisterMetaType<MyClass&>("MyClassRef"); it can't be compiled.

and i found the following code works:

bool con = connect(thread, SIGNAL(mysignal3(MyClass)), this, SLOT(myslot3(MyClass)), Qt::BlockingQueuedConnection);

here is the code where the thread is created and started:


testsignals::testsignals(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);

MyThread *thread = new MyThread(this);

qRegisterMetaType<MyClass>();

bool con;
con = connect(thread, SIGNAL(mysignal1(int)), this, SLOT(myslot1(int)), Qt::BlockingQueuedConnection);
con = connect(thread, SIGNAL(mysignal2(MyClass &)), this, SLOT(myslot2(MyClass &)), Qt::BlockingQueuedConnection);


thread->start();
thread->wait();
}



and here is the thread's run procedure:


void MyThread::run()
{
emit mysignal1(44);

MyClass m;
emit mysignal2(m);
}


i know passing stack allocated data by reference isn't good, but just for test...

wysota
2nd March 2011, 12:59
It's not about stack or non-stack. It's about mutable and non-mutable. A reference to an object is mutable, a copy of the object is not. Thus the latter works and the former doesn't.

And your thread affinity is ok - the Thread object works in context of the main thread and the "m" object works in context of the worker thread.

mentalmushroom
2nd March 2011, 15:34
ok, but is there any way to pass a reference or const reference to signal/slot? actually i need to pass a QExplicitlySharedPointer as a signal/slot argument, and it seems if i don't pass it as a reference, i have to implement a copy constructor and possibly assignment operator that is inconvenient when such signal/slots are used in a several different classes with a lot of member values.

wysota
2nd March 2011, 15:40
A const reference is not a problem, it should work out of the box. Passing a reference doesn't make sense. As I said, before reaching the slot, the data will be copied so you'd operate on a copy anyway. Better use pointers. But before you do that, as I already said, think a couple of times if signals are a good approach here. It might be much easier to do what you want using events, for instance like this:

MyEvent event;
event.setSomeData(data);
QApplication::sendEvent(someObjectInAnotherThread, &event); // this will block
data = event.data(); // modified content

or using a classical approach with a wait condition blocking the sending thread.

mentalmushroom
10th November 2011, 11:10
strange, i've just noticed when calling QCoreApplication::sendEvent on some object in another thread the following error appears: "ASSERT failure in QCoreApplication::sendEvent: Cannot send events to objects owned by a different thread. …"7087

wysota
10th November 2011, 13:17
Yes, unfortunately that's true. But you can have the same effect using a wait condition. Post the event, wait on the condition until it is signalled by the handling object when the data is ready.