Results 1 to 14 of 14

Thread: Signals are delayed on X11?

  1. #1
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    383
    Thanks
    99
    Thanked 14 Times in 14 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Signals are delayed on X11?

    I observed the following behaviour when running an application with background threads on Linux:

    I start a thread with the press of a button. The thread emits hundreds of signals with a very fast pace (12 ms). The signals are connected to the slot of another thread, which is already running, but the signals do not arrive. Only when I click somewhere on the gui again, suddenly a signal havoc reaches the second thread. It seems to me that the signals from the first thread were delayed, until I did something with the gui, then suddenly all the signals were handled at once. This does not happen on Windows.

    Is there anything I can do to force the signals to be handled immidiately?

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Signals are delayed on X11?

    You might try not to starve one thread by eating all the cpu time in the other one. Use a lower priority or do something else to make sure the main thread gets its slice of cpu sometimes.

  3. #3
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    383
    Thanks
    99
    Thanked 14 Times in 14 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Signals are delayed on X11?

    Both threads are actually quite lightweight. The one does some short calculation with a 12 ms sleep and the other handles serial communication by sending and receiving a 60 byte packet with 20 ms sleep. But well, as for your usual advice, I will see if I can make an improvement with a timer based approach.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Signals are delayed on X11?

    Could you show us the thread object creation and connect statement code?

  5. #5
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    383
    Thanks
    99
    Thanked 14 Times in 14 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Signals are delayed on X11?

    Certainly. The complete code of the two threads is attached. And here is some more explanation for easier understanding.

    My software is a motion editor for a humanoid robot. The robot is connected to the PC on a serial port. The idea is to move the robot's body with your hands and record the robot's poses (sets of joint angles) in the meantime. At a later time you can play back a sequence of poses and the robot will execute it and perform the same motion that you showed it with your hands. The robot is also virutally visualized with a 3D skeleton on the screen and lots of spin boxes are showing the current joint angle values.

    Attached you will find the classes of two threads. The RobotInterface is handling the serial communication. It's active the whole time, it constantly exchanges packets with the robot at a pace of approx. 20 ms. The KeyframePlayer is triggered by the press of a button on the gui. It takes the currently loaded motion sequence, samples it with a pace of 12 ms, generates joint angles and gives them to the RobotInterface to be sent to the robot.

    The connecting code I will show you right here:

    Qt Code:
    1. /*
    2.  * Starts playing the keyframes in the motion sequence.
    3.  * The keyframe player gets connected to the robot interface and to the keyframe editor.
    4.  * Attention! If the robot is actuated, it will execute the current motion.
    5.  */
    6. void MotionEditor::on_playButton_clicked()
    7. {
    8. // Abort if already running.
    9. if (keyframePlayer.running)
    10. {
    11. playerDone();
    12. }
    13.  
    14. else
    15. {
    16. //connect(&keyframePlayer, SIGNAL(jointAnglesChanged(QHash<QString, float>)),
    17. &robotInterface, SLOT(setTxJointAngles(QHash<QString, float>)));
    18.  
    19. // Start the player thread.
    20. keyframePlayer.playTheseFrames(motionSequence->getKeyframes());
    21. }
    22. }
    To copy to clipboard, switch view to plain text mode 

    Well it's a bit boring right now, because I commented the connect() call out. The reason is the problem I described. Since I found transfering the data by signals and slots to be unreliable for now, I changed the KeyframePlayer a bit and added direct calls to the RobotInterface. If you search for the keyword "setTxJointAngles" in KeyframePlayer, you will find all the relevant spots. The signals are still emitted though, it's only the connect() call above that I commented out for now.


    I will be happy if you actually take a look at it and provide some guru advice.

    While I already know I have it coming, yes, thread safety is actually an issue that I haven't addressed yet. What I did so far is I pass a jointAngles QHash by value from the KeyframePlayer to the RobotInterface. The RobotInterface reads it and sends it to the robot. In the meantime it's very likely, that the KeyframePlayer overwrites the very same QHash. I was hoping that implicit sharing will be good enough, but it's not the case. The software crashes many times at this point. I'm not sure yet how I can solve this problem in a nice way, so if you can throw me a penny, I will be very thankful.
    Attached Files Attached Files

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Signals are delayed on X11?

    Ok, three things.

    1. I wouldn't transmit a QHash object across signals/slots between threads because at least one of two reasons - thread safety (two threads accessing a single object at the same time) or performance (serializing and deserializing the hash). Maybe you should have a single shared buffer (it can be a QHash object) protected with a mutex where you store values and signal the other thread they are ready.

    2. Your thread objects probably live in the main thread so all signals emitted by them and all slots they contain are executed in the context of the main thread and not your "worker" threads which is probably not what you want. You should use QObject::moveToThread() to push those objects to their respective threads.

    3. When you do what I said in the previous point, you will probably notice your slots are not executed at all. That's because a thread needs an event loop running to be able to execute slots across threads so you need to change your approach to an event driven one at least in the thread you want to process signals from other threads. It shouldn't be too hard in your case - just call exec() from run() and use timers with appropriate timeouts (like 12ms and 0 or more) to do your work.

  7. #7
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    383
    Thanks
    99
    Thanked 14 Times in 14 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Signals are delayed on X11?

    I'm sorry, I don't really understand any of those things.

    1. I wouldn't transmit a QHash object across signals/slots between threads because at least one of two reasons - thread safety (two threads accessing a single object at the same time) or performance (serializing and deserializing the hash).
    The thread safety is clear. The serialization is not. The QHash is serialized when I pass it by value? Because here it says that due to implicit sharing it's actually just like passing only a pointer. And here it even explicitly says that it's safe to pass implicitly shared containers between threads (does not imply thread safety).

    2. Your thread objects probably live in the main thread so all signals emitted by them and all slots they contain are executed in the context of the main thread and not your "worker" threads which is probably not what you want. You should use QObject::moveToThread() to push those objects to their respective threads.
    Yes this is true, the QThread objects are created and started from the main thread. What does it mean that "all signals emitted by them and all slots they contain are executed in the context of the main thread"? Why is it not what I want?

    Point 3. I probably don't even need to think about until I understand point 2.


    In any case, I found the reason why my signals were behaving so strange. It's embarassing, but the truth is that there was a mistake in my code. Here is the culprit:

    Qt Code:
    1. while (jointIterator.hasNext())
    2. {
    3. jointIterator.next();
    4. jointAngles[jointIterator.key()] += steps[jointIterator.key()];
    5. emit jointAnglesChanged(jointAngles);
    6. }
    To copy to clipboard, switch view to plain text mode 

    The signal was sent out for every single joint instead of just once after all joint angles have been changed. 20 signals every 12 ms are a lot. Actually it should read:

    Qt Code:
    1. while (jointIterator.hasNext())
    2. {
    3. jointIterator.next();
    4. jointAngles[jointIterator.key()] += steps[jointIterator.key()];
    5. }
    6.  
    7. emit jointAnglesChanged(jointAngles);
    To copy to clipboard, switch view to plain text mode 

    So now that I fixed this everything works like expected on Windows and on Linux.

  8. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Signals are delayed on X11?

    Quote Originally Posted by Cruz View Post
    The thread safety is clear. The serialization is not. The QHash is serialized when I pass it by value?
    It is serialized when you use queued (across threads) signal-slot connections. The data has to be stored somewhere so that the other thred can use it when it decides to handle a signal event. This is to assure thread-safety and object consistency.

    Because here it says that due to implicit sharing it's actually just like passing only a pointer. And here it even explicitly says that it's safe to pass implicitly shared containers between threads (does not imply thread safety).
    Yes, that's all true but it doesn't say what happens if signal-slot mechanism across threads kicks in. Implicit sharing still helps but remember you may be trying to access (modify) the same object from different threads so it is safe to assume you receive a detached copy of the object in the slot which requires a deep copy. This isn't that expensive with QHash especially if it has 20 cells but if you do that 50 times per second, the overall cost can be significant.

    What does it mean that "all signals emitted by them and all slots they contain are executed in the context of the main thread"?
    Read about "thread affinity" and "queued connections" in Assistant.

    Why is it not what I want?
    Because it can break your application and it makes the use of threads somewhat questionable if you access the main thread from worker threads.

    Point 3. I probably don't even need to think about until I understand point 2.
    Just try it and see for yourself. You can also test it by blocking the event loop of the main thread - you will see the slots won't be executing at all.

    So now that I fixed this everything works like expected on Windows and on Linux
    But the questionable design of emitting signals on behalf of wrong threads remains. You might stumble upon this problem later on when your application becomes more complex and it will be much more expensive to solve it then, so it's better to handle it now.

  9. The following user says thank you to wysota for this useful post:

    Cruz (17th February 2009)

  10. #9
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    383
    Thanks
    99
    Thanked 14 Times in 14 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Signals are delayed on X11?

    Ok I understand thread affinity and thread event loops now.

    The two Qthreads are both created in the main thread. The internal objects the threads use are created in the thread where appropriate. So there is nothing I would need to move to a thread.

    The internal objects of the threads don't need any signal handling, so the threads don't need any event loops. The signals of the threads themselves should be queued by the main thread, so everything is ok about this.

    The only thing left is to take care of thread safety, when one thread passes a QHash to the other. I started a new topic about this, because this one was actually about delayed signals in X11.

  11. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Signals are delayed on X11?

    Quote Originally Posted by Cruz View Post
    The two Qthreads are both created in the main thread. The internal objects the threads use are created in the thread where appropriate. So there is nothing I would need to move to a thread.
    Do you emit signals on behalf of the "internal objects" or the thread object? If "RobotInterface" and "KeyframePlayer" inherit QThread then you are exactly in the situation I'm talking about.

    The internal objects of the threads don't need any signal handling, so the threads don't need any event loops. The signals of the threads themselves should be queued by the main thread, so everything is ok about this.
    I'm not sure you are right. It would be easier to talk about it if you provided header files for both your classes.

    The only thing left is to take care of thread safety, when one thread passes a QHash to the other.
    The only clash that may occur in current situation is when emitting the signal carrying the hash but only if you access the same instance of QHash at some other place in code. As long as you use local objects only and make sure they are detached from other instances before emitting them, you should be safe. Just know it's a bad design which can turn into obstacle later on.

  12. #11
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    383
    Thanks
    99
    Thanked 14 Times in 14 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Signals are delayed on X11?

    I attached the header files.

    All the signals coming from those threads are targeted at the main thread. Except for one, which is the signal that carries the joint angles from the KeyframePlayer thread to the RobotInterface thread. So the point you are trying to make is that I should actually queue this one signal and handle it in the RobotInterface's event loop? I still don't understand why it's a bad thing if the main thread handles the signal. What exactly goes wrong?
    Attached Files Attached Files

  13. #12
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Signals are delayed on X11?

    Quote Originally Posted by Cruz View Post
    All the signals coming from those threads are targeted at the main thread.
    That doesn't matter. The thing that matters is where they originate from and that seems to be the thread object which lives in the main thread.

    Except for one, which is the signal that carries the joint angles from the KeyframePlayer thread to the RobotInterface thread.
    Which is currently handled by the main thread as well.

    So the point you are trying to make is that I should actually queue this one signal and handle it in the RobotInterface's event loop?
    I mean you should have an event loop there in the first place. And when you do, push the thread object to its thread so that it can handle its signals and slots properly.

    I still don't understand why it's a bad thing if the main thread handles the signal. What exactly goes wrong?
    It's the slot I'm more worried about. The thing is you access the "txJointAngles" variable from both the main thread and the worker thread. It may happen that you iterate over the container in the "poseDistance" method and at the same time "overwrite" it with a new object using the slot ran by the main thread. This is a classical example of accessing a single variable from multiple threads and requires synchronization. If you not synchronize the threads, the least that can happen is a wrong result of poseDistance() or wrong execution of transmit() (as they both access the variable) and at worst your application will eventually crash (well... that's not the worst at all that can happen but it's still bad).


    By the way, if you keep a pointer to the robot interface in the player, there is no point in using signals and slots. Either get rid of that dependency or call appropriate methods directly (probably guarding access to a shared variable with a mutex or such).

  14. The following user says thank you to wysota for this useful post:

    Cruz (18th February 2009)

  15. #13
    Join Date
    Jan 2009
    Location
    Germany
    Posts
    383
    Thanks
    99
    Thanked 14 Times in 14 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Signals are delayed on X11?

    I mean you should have an event loop there in the first place. And when you do, push the thread object to its thread so that it can handle its signals and slots properly.
    Aaaah that was enlightening! Or maybe because my brain is fresh now in the morning. You mean I should push the QThread objects into themselves to handle their own signals! In consequence, doesn't it mean that you should ALWAYS do that, whenever you are using threads?

    So if I understand right, signals between threads are always queued by default, no matter if it's between a worker thread and the main thread or between two worker threads. The difference it makes is that if a thread handles its own events, you eliminate the possibility of the main thread calling a slot of a worker thread at the wrong time. Is this correct?

    t's the slot I'm more worried about. The thing is you access the "txJointAngles" variable from both the main thread and the worker thread.
    Yes this is true. As I already said, I haven't addressed the thread safety problem at that time. The application does crash. A lot. As performance is somewhat crucial, I wanted to try to find a way without mutexes. I would prefer a thread not to block and wait for a mutex to open, but to go ahead and calculate the next joint angles in the meantime.

    Another thing about mutexes that bothers me is that they need to be global variables known to both threads. At least that's what I saw in the examples and the documentation. The most elegant solution would be something completely contained in one thread, without the other knowing about it.

    By the way, if you keep a pointer to the robot interface in the player, there is no point in using signals and slots.
    Yes this is also true. The reference is still there because of my poor signal handling that caused the problems in the original post in this topic. If I can rely on my signals being "snappy", then I would prefer to get rid of the reference and hace completely indepedent objects.

  16. #14
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,364
    Thanks
    3
    Thanked 5,014 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Signals are delayed on X11?

    Quote Originally Posted by Cruz View Post
    In consequence, doesn't it mean that you should ALWAYS do that, whenever you are using threads?
    No, that's not always desired. For instance if the thread object has a parent, you can't push it to another thread. Furthermore the thread object is only a controller of the thread so it doesn't have to always be tied up closely to the thread itself.

    So if I understand right, signals between threads are always queued by default, no matter if it's between a worker thread and the main thread or between two worker threads.
    Yes, that's right. Read about "auto connections" of signals.

    The difference it makes is that if a thread handles its own events, you eliminate the possibility of the main thread calling a slot of a worker thread at the wrong time. Is this correct?
    Yes.


    As performance is somewhat crucial, I wanted to try to find a way without mutexes. I would prefer a thread not to block and wait for a mutex to open, but to go ahead and calculate the next joint angles in the meantime.
    So use tryLock() instead of lock() on the producer side.

    Another thing about mutexes that bothers me is that they need to be global variables known to both threads.
    That doesn't have to be true. You can have a mutex within a singleton class.

    The most elegant solution would be something completely contained in one thread, without the other knowing about it.
    If that was the case, you wouldn't be accessing the variable you want to protect from another thread. If you want an elegant solution, consider using shared memory (QSharedMemory) to transfer data between threads or processes. You can then split your application into two separate applications - one for performing calculations and the other for driving the robot.

  17. The following user says thank you to wysota for this useful post:

    Cruz (18th February 2009)

Similar Threads

  1. Signals and Slots Problem
    By GenericProdigy in forum Qt Programming
    Replies: 4
    Last Post: 2nd February 2009, 09:06
  2. Signals and Slots
    By 83.manish in forum Qt Programming
    Replies: 3
    Last Post: 30th June 2008, 10:31
  3. Problem with SpinBox signals and slots
    By ramstormrage in forum Newbie
    Replies: 4
    Last Post: 2nd May 2008, 01:45
  4. QThread and signals (linux/UNIX signals not Qt Signals)
    By Micawber in forum Qt Programming
    Replies: 1
    Last Post: 28th November 2007, 22:18
  5. KDE Signals
    By chombium in forum KDE Forum
    Replies: 1
    Last Post: 25th January 2006, 18:45

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.