PDA

View Full Version : [QT4] threads, signals, and slots, please help.



ucntcme
24th January 2006, 10:38
I am in learning Qt phase here, so please bear with me. :)

Imagine a threaded fortune server that serves a different fortune base don a strign you send to it when you conenct. Got the idea? Good.

Now, here is the general shape of what I have:

main_thread

(QtCoreApplication used, no GUI at all)
QTcpServer based class

FortuneDBServerObject (not a *network* server)
connection threads (one per connection)


Essentially the connection threads are "siblings" of the db object, and all are children of the QTcpServer object.

What I need to do is pass a QString (call it StringA) from a connection thread to the FortuneDBServer, and get a response (StringB) back.

I figured I could use a direct connection on the signal to send StringA to the fortunedb object (QObject) with a return value of StringB. Initially I set the signal up inside the thread but that failed wonderfully (i.e. appeared to work but did not). Now I am trying to connect the signal in the QTcpServer class and it is simply nto getting called. At the moment I've changed the dbserver slot to only print it was called and return a static string, just to verify it gets called. Which it does not. No errors, no warnings it just never calls it.

I've tested the networking separately and it all works perfectly. I've even tested the dbserver seperately and it also works perfectly. It is solely the communication bewteen the two I am having difficulty with.

Links, pointers, and example code welcome. Even if it means redesigning it because I have the wrong "model". ;)

wysota
24th January 2006, 11:23
Can you post some code of yours here?

ucntcme
24th January 2006, 12:12
Can you post some code of yours here?
Which part(s) do you want?

In the connection thread I have this:


if ( has_target ) {
cout << "Have target. " ;
if ( have_terminator ) {
cout << "Have terminator " <<endl;
action = emit getActionForTarget(target);


Which as you can see is where the signal is emitted. The couts before and after the emit do indeed print out.

The QTcpServer based class has:


void Server::incomingConnection(int socketDescriptor) {
DBServerA* dbserver = &db;
ConnectionThread *thread = new ConnectionThread(socketDescriptor, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()), Qt::DirectConnection );
connect(thread, SIGNAL(getActionForTarget()), dbserver, SLOT(getActionForTarget()), Qt::DirectConnection );
thread->start();
}


and the slot in the dbserver (a QObject) is:


int DBServerA::getActionForTarget( QString target ) {
qDebug() << "getAction called for target" <<target <<endl;
int action = 0;
}


(Yes other debug statements are showing up. ;) )
The original code for the tcpserver came from the qt-interest list, (http://lists.trolltech.com/qt-interest/2005-10/thread01010-0.html) and as I said works exactly as expected ... except of course that the signal to the dbobject does seem to be getting emitted (or maybe it is but nobody is listening).

Codepoet
24th January 2006, 12:22
You connected the signal

getActionForTarget()
instead of

getActionForTarget(QString)
You have to fix the SIGNAL and the SLOT. And why do you use direct connections? You can use those only securely when the sending and receiving object are owned by the current thread. Just use the default - Qt should do the right thing ;)

Do you call QThread::exec in your threads to allow event processing of queued events?

ucntcme
24th January 2006, 13:59
And why do you use direct connections?

Well that's what the advice was in the link I listed. ;)

As far as calling exec ... no, but other signals/slots are working fine (i.e. the signals from the socket).

.... Added QString as you said and it is now working. Thanks. Why didn't that throw some error or warning at compile time?

wysota
24th January 2006, 14:02
action = emit getActionForTarget(target);

Since when does "emit" have a return value? :)

Maybe you should just "register" an object will return the action and call it directly here instead of such weird statements as the one above?

ucntcme
24th January 2006, 14:04
The slot is being activated as desired, and has an appropriate return value, but back in the connection thread, the value I get is NOT what I expect. I am expecting an int back, and well I get a number but it isn't the single digit int I send back.

a..l..m..os..t..there

wysota
24th January 2006, 14:05
The slot is being activated as desired, and has an appropriate return value, but back in the connection thread, the value I get is NOT what I expect. I am expecting an int back, and well I get a number but it isn't the single digit int I send back.

a..l..m..os..t..there

Probably because return values from slots are ignored and you get a random value here. Look at my previous post, I suggested a solution there.

ucntcme
25th January 2006, 04:05
action = emit getActionForTarget(target);

Since when does "emit" have a return value? :)


Since I wanted it to, naturally. ;)

Actually, I was mislead by statements (elsewhere) that emit was "just a decoration for the programmer", that the signal was still "just a function call". I was actually thiking about this last night while sleeping and thinking of alternate routes of getting the data back to the connection thread.



Maybe you should just "register" an object will return the action and call it directly here instead of such weird statements as the one above?

As soon as I figure out just what you mean, I'm sure I'll try it. :)

Thanks again.

Cheers,
Bill

wysota
25th January 2006, 10:24
Since I wanted it to, naturally. ;)

Actually, I was mislead by statements (elsewhere) that emit was "just a decoration for the programmer", that the signal was still "just a function call".

It is (usually) a function call. But! What happens if there are two or more slots connected to a signal? Return value of which of them should then be returned?


As soon as I figure out just what you mean, I'm sure I'll try it. :)

I mean to pass a pointer or reference of the object which is to deliver some information to the other one. This way you'll be able to call the method directly on a single object, without signal/slot mechanism:


struct aaa {
int action(someclass &);
};

class bbb {
public:
void registerDeliverer(aaa *a){ m_ad = a; }
void do_something();
private:
aaa *m_ad;
}

void bbb::do_something(){
//...
if(!m_ad)
return;
int act = m_ad->action(); // fetch an int from registered object
//...
}
//...
aaa action_deliverer;
bbb obj;
//...
obj->registerDeliverer(&action_deliverer);
//...
obj->do_something();
//...

ucntcme
25th January 2006, 13:37
It is (usually) a function call. But! What happens if there are two or more slots connected to a signal? Return value of which of them should then be returned?


Well obviously the only one I am interested in! :D

Seriously though, that makes sense explained that way.
Perhaps it would be nice if a warning/error was issued at compile time if a signal was declared as anything other than void? As a newbie that would make some sense to me, and would have alerted me to the head-banging route I was travelling upon. :)




I mean to pass a pointer or reference of the object which is to deliver some information to the other one. This way you'll be able to call the method directly on a single object, without signal/slot mechanism:


struct aaa {
int action(someclass &);
};

class bbb {
public:
void registerDeliverer(aaa *a){ m_ad = a; }
void do_something();
private:
aaa *m_ad;
}

void bbb::do_something(){
//...
if(!m_ad)
return;
int act = m_ad->action(); // fetch an int from registered object
//...
}
//...
aaa action_deliverer;
bbb obj;
//...
obj->registerDeliverer(&action_deliverer);
//...
obj->do_something();
//...



I suspected that was what you meant, and had begun working on that. Of course, I've done it wrong and get segfaults, but I'm sure it's not a Qt related segfault, rather programmer naivete. ;) Some of it I just *have* to bang away at until I get it. But then again, once I get it, I've got it. Know what I mean?


But one quick question on the above ... what is "someclass" representing?

wysota
25th January 2006, 15:05
Perhaps it would be nice if a warning/error was issued at compile time if a signal was declared as anything other than void? As a newbie that would make some sense to me, and would have alerted me to the head-banging route I was travelling upon. :)

No, because slots are regular methods, just with additional capabilities. You can invoke them as normal methods and use their return values as usual.


But one quick question on the above ... what is "someclass" representing?

Some data which is processed by "action" method... That's just an example, nothing specific.

ucntcme
25th January 2006, 15:23
No, because slots are regular methods, just with additional capabilities. You can invoke them as normal methods and use their return values as usual.


Well it was a nice thought anyway. ;)



Some data which is processed by "action" method... That's just an example, nothing specific.

Well I finally found the route out of segfault land (a nap can do wonders ;) ) and it is all working perfectly. Thanks again!