Page 1 of 2 12 LastLast
Results 1 to 20 of 26

Thread: Preventing a Slot to be called again before it has finished running

  1. #1
    Join Date
    Mar 2012
    Posts
    16
    Thanks
    15
    Qt products
    Qt4
    Platforms
    Windows

    Default Preventing a Slot to be called again before it has finished running

    Hi,

    Normally when a Widget's signal (f.e QSlider's valueChanged(int) signal) is connected to a given Slot, then this slot is not called again by the same signal as long as it has not returned.

    This means that if you are moving the QSlider faster than its corresponding slot can run, your QSlider will simply "lag" when you move it becaise it will wait for the slot to follow. You can't move it faster than the Slot can run. This will allows the QSlider and its Slot to stay well synch.

    Now, I have noticed that if a slot contains a call to some external DLL function, then this is not true anymore: multiple re-entrant calls can be done on this slot by the same widget's signal! This is extremely annoying in case of a QSlider moving faster than its slot can run because the Slot is re-called before it has finished running, thus making some sort of recursive or re entrant calls. It's like if the dll call inside the Slot was "broken" as it runs by the event loop or something. What is causing this curious behavior and how to prevent it? (of course I can always block or break the Widget's signal-slot connection inside its own slot and reactivate it as the slot is finished, or even disable the widget as the slot is running, but maybe there is a much nicer/cleaner way?)

    --
    mk

  2. #2
    Join Date
    Sep 2011
    Posts
    1,241
    Thanks
    3
    Thanked 127 Times in 126 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    I think there is something else going on there...

    No matter whether connections are synchronous or asynch, a signal cannot be fired again until the previous signal has returned.

    I think a screen shot of a call stack would be handy.
    If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

  3. The following user says thank you to amleto for this useful post:

    MattK (17th April 2012)

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

    Default Re: Preventing a Slot to be called again before it has finished running

    Are you using threads in your application? There is simply no way a single slot can be called concurrently if things were done properly (that is if you're not using direct connections across threads).
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


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

    MattK (17th April 2012)

  6. #4
    Join Date
    Mar 2012
    Posts
    16
    Thanks
    15
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Quote Originally Posted by amleto View Post
    ...
    I think a screen shot of a call stack would be handy.
    Hi amleto, thanks for the suggestion. I did it.

    So below is the code that gives the evidence (or at least the impression) that the slot was re-entered, using a re-entrance counter variable:


    Qt Code:
    1. // Well, yes I know I should give the complete code, but it's really huge :(
    2.  
    3. SelectSource::SelectSource(QWidget *parent)
    4. : QWidget(parent)
    5. {
    6. n = 0; // slot re-entrancy counter
    7. ...
    8. }
    9.  
    10. void SelectSource::createToolbar()
    11. {
    12. ...
    13. connect(qSliderFocus, SIGNAL(valueChanged(int)), this, SLOT(updateFocusLabel())); // there is no other signal connected to this slot nor any direct call to this slot.
    14. ...
    15. }
    16.  
    17. void SelectSource::updateFocusLabel()
    18. {
    19. if (n)
    20. if (globalConsole)
    21. globalConsole->sendMsg(QObject::tr("n==%1, meaning this slot was re-entered before it finished").arg(n)); /* Normally impossible to reach. Break Point line was set here */
    22.  
    23. if (globalConsole)
    24. globalConsole->sendMsg(QObject::tr("Start focus loop..."));
    25.  
    26. n++; // should be == 1, never more
    27.  
    28.  
    29. // This calls a DLL function. Content of DLL function closed and unknown to me.
    30. // Note that this dll function has a timeout argument in its parameter.
    31. // This means there is maybe some multithread logic hidden behind. Still, this does not explain why the slot updateFocusLabel() is re-entered.
    32.  
    33. focusCam();
    34.  
    35. n--; // must get back to 0.
    36.  
    37. if (globalConsole)
    38. globalConsole->sendMsg(QObject::tr("Stop focus loop."));
    39.  
    40. }
    To copy to clipboard, switch view to plain text mode 

    And then the stack as given by netbeans using MinGW (windows is large, please scroll horizontally) + breakpoint at line 21 on the code above. I do not see a clear re-entrancy in the slot through this stack, but still, if I reached this breakpoint it means that n>0 when starting the slot() so that the slot was re-entered before it finished.
    Yes, app is single threaded.

    Qt Code:
    1. org.netbeans.modules.viewmodel.TreeModelNode@e3eed5[Name=, displayName=SelectSource::updateFocusLabel(this=0xc8730e8) at selectsource.cpp:202] C:\\Users\\Matt-usr\\Documents\\CTA\\ProjectFiles\\QtIRView\selectsource.cpp:202
    2. org.netbeans.modules.viewmodel.TreeModelNode@550a69[Name=, displayName=SelectSource::qt_metacall(this=0xc8730e8,_c=QMetaObject::InvokeMetaMethod,_id=11,_a=0x22a408) at moc.tmp/moc_selectsource.cpp:107] C:\\Users\\Matt-usr\\Documents\\CTA\\ProjectFiles\\QtIRView\moc.tmp\moc_selectsource.cpp:107
    3. org.netbeans.modules.viewmodel.TreeModelNode@11e9fc6[Name=, displayName=QMetaObject::metacall(object=0xc8730e8,cl=QMetaObject::InvokeMetaMethod,idx=38,argv=0x22a408) at kernel\\qmetaobject.cpp:237] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qmetaobject.cpp:237
    4. org.netbeans.modules.viewmodel.TreeModelNode@18bb614[Name=, displayName=QMetaObject::activate(sender=0xc8c45d8,m=0x13dedc0,local_signal_index=0,argv=0x22a408) at kernel\\qobject.cpp:3278] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qobject.cpp:3278
    5. org.netbeans.modules.viewmodel.TreeModelNode@15f08f9[Name=, displayName=QAbstractSlider::valueChanged(this=0xc8c45d8,_t1=888) at tmp\\moc\\debug_shared\\moc_qabstractslider.cpp:182] C:\Users\Matt-usr\Documents\CTA\bin\tmp\\moc\\debug_shared\\moc_qabstractslider.cpp:182
    6. org.netbeans.modules.viewmodel.TreeModelNode@464666[Name=, displayName=QAbstractSlider::setValue(this=0xc8c45d8,value=888) at widgets\\qabstractslider.cpp:543] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qabstractslider.cpp:543
    7. org.netbeans.modules.viewmodel.TreeModelNode@1b80e2d[Name=, displayName=QAbstractSlider::triggerAction(this=0xc8c45d8,action=QAbstractSlider::SliderMove) at widgets\\qabstractslider.cpp:632] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qabstractslider.cpp:632
    8. org.netbeans.modules.viewmodel.TreeModelNode@aac5db[Name=, displayName=QAbstractSlider::setSliderPosition(this=0xc8c45d8,position=888) at widgets\\qabstractslider.cpp:500] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qabstractslider.cpp:500
    9. org.netbeans.modules.viewmodel.TreeModelNode@1a3c2bf[Name=, displayName=QSlider::mouseMoveEvent(this=0xc8c45d8,ev=0x22abfc) at widgets\\qslider.cpp:514] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qslider.cpp:514
    10. org.netbeans.modules.viewmodel.TreeModelNode@46a30e[Name=, displayName=QWidget::event(this=0xc8c45d8,event=0x22abfc) at kernel\\qwidget.cpp:8244] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qwidget.cpp:8244
    11. org.netbeans.modules.viewmodel.TreeModelNode@17b28cc[Name=, displayName=QAbstractSlider::event(this=0xc8c45d8,e=0x22abfc) at widgets\\qabstractslider.cpp:942] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qabstractslider.cpp:942
    12. org.netbeans.modules.viewmodel.TreeModelNode@b3751f[Name=, displayName=QSlider::event(this=0xc8c45d8,event=0x22abfc) at widgets\\qslider.cpp:435] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qslider.cpp:435
    13. org.netbeans.modules.viewmodel.TreeModelNode@1ce51dd[Name=, displayName=QApplicationPrivate::notify_helper(this=0x3f3a78,receiver=0xc8c45d8,e=0x22abfc) at kernel\\qapplication.cpp:4462] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication.cpp:4462
    14. org.netbeans.modules.viewmodel.TreeModelNode@60b54e[Name=, displayName=QApplication::notify(this=0x22ff20,receiver=0xc8c45d8,e=0x22abfc) at kernel\\qapplication.cpp:4023] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication.cpp:4023
    15. org.netbeans.modules.viewmodel.TreeModelNode@11f4657[Name=, displayName=QCoreApplication::notifyInternal(this=0x22ff20,receiver=0xc8c45d8,event=0x22abfc) at kernel\\qcoreapplication.cpp:731] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qcoreapplication.cpp:731
    16. org.netbeans.modules.viewmodel.TreeModelNode@431814[Name=, displayName=QCoreApplication::sendSpontaneousEvent(receiver=0xc8c45d8,event=0x22abfc) at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:218] C:\Users\Matt-usr\Documents\CTA\bin\..\..\include\QtCore\..\..\src\corelib\kernel\qcoreapplication.h:218
    17. org.netbeans.modules.viewmodel.TreeModelNode@e1ca35[Name=, displayName=QApplicationPrivate::sendMouseEvent(receiver=0xc8c45d8,event=0x22abfc,alienWidget=0xc8c45d8,nativeWidget=0x22feb0,buttonDown=0x15db41c,lastMouseReceiver=@0x15db420: {o = 0xc8c45d8},spontaneous=true)
    18. at kernel\\qapplication.cpp:3120] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication.cpp:3120
    19. org.netbeans.modules.viewmodel.TreeModelNode@1a25f0d[Name=, displayName=QETWidget::translateMouseEvent(this=0x22feb0,msg=@0x22b0f8: {hwnd = 0x150374, message = 512, wParam = 1, lParam = 2163086, time = 2273640, pt = {x = 398, y = 55}})
    20. at kernel\\qapplication_win.cpp:3321] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication_win.cpp:3321
    21. org.netbeans.modules.viewmodel.TreeModelNode@10e69fd[Name=, displayName=QtWndProc@16(hwnd=0x150374,message=512,wParam=1,lParam=2163086) at kernel\\qapplication_win.cpp:1659] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication_win.cpp:1659
    22. org.netbeans.modules.viewmodel.TreeModelNode@1507d48[Name=, displayName=USER32!IsWindowVisible()] C:\\Windows\\system32\\user32.dll
    23. org.netbeans.modules.viewmodel.TreeModelNode@1510be0[Name=, displayName=Address: [@0x00150374]]
    24. org.netbeans.modules.viewmodel.TreeModelNode@1e2a3e7[Name=, displayName=Address: [@0x00000200]]
    25. org.netbeans.modules.viewmodel.TreeModelNode@76a726[Name=, displayName=USER32!IsWindowVisible()] C:\\Windows\\system32\\user32.dll
    26. org.netbeans.modules.viewmodel.TreeModelNode@1d7b83b[Name=, displayName=qt_is_translatable_mouse_event(message=0) at kernel\\qapplication_win.cpp:1426] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication_win.cpp:1426
    27. org.netbeans.modules.viewmodel.TreeModelNode@180599e[Name=, displayName=USER32!IsWindowVisible()] C:\\Windows\\system32\\user32.dll
    28. org.netbeans.modules.viewmodel.TreeModelNode@17bd470[Name=, displayName=Address: [@0x00000000]]
    To copy to clipboard, switch view to plain text mode 

    Well, it's like if the DLL call was fooling the signal-slot mechanism and would make the QSlider believe the slot is finished when it's not.

    Quote Originally Posted by wysota View Post
    Are you using threads in your application? There is simply no way a single slot can be called concurrently if things were done properly (that is if you're not using direct connections across threads).
    Hi wysota,

    I said before I was not using threads. Well, I use threads but not for this signal->slot connection. The thread I use is communicating through normal connections, that are normally queued by default when Qt detects it's a crossthread connect.

    Here is the only threaded code I use, unrelated to this issue i think:

    Qt Code:
    1. SelectSource::SelectSource(QWidget *parent)
    2. : QWidget(parent)
    3. {
    4. ...
    5.  
    6. QThread *thread = new QThread;
    7. getRingElement = new GetRingElement(); // must not have a parent as this would prevent moveToThread() working
    8.  
    9. connect(getRingElement, SIGNAL(msg4console(QString)), globalConsole, SLOT(sendMsg(QString)));
    10. connect(this, SIGNAL(updateACQThreadRE(bool, int, int, int)), getRingElement, SLOT(setRE(bool, int, int, int)));
    11. connect(this, SIGNAL(startACQThreadTimer(int)), getRingElement, SLOT(start(int)));
    12. connect(this, SIGNAL(stopACQThreadTimer()), getRingElement, SLOT(stop()));
    13. getRingElement->moveToThread(thread); // hmm well maybe I should connect only after the code is moved to a separated thread to ensure the queued mode is activated. I could also simply give the queued mode explicitly.
    14. thread->start();
    15. ...
    16. }
    To copy to clipboard, switch view to plain text mode 

    Coming back to the re-entered slot, here is the DLL function called:

    Qt Code:
    1. in a .h:
    2.  
    3. extern int (_stdcall * vc_operate_command)(int Handle,char * Command,char * Answer,const int TimeOut);
    4.  
    5. in a .cpp:
    6.  
    7. int (_stdcall * vc_operate_command)(int Handle,char * Command,char * Answer,const int TimeOut)=NULL;
    8.  
    9. in another .cpp:
    10.  
    11. vc_operate_command = (int (_stdcall *)(int, char *, char *, const int))GetProcAddress(hInstance,"vc_operate_command");
    12.  
    13. Now when used, the command is called as:
    14.  
    15. result = vc_operate_command(Vcam->Handle, (char*)(command.toAscii()).constData(), answer, TIMEOUT_ANS);
    To copy to clipboard, switch view to plain text mode 

    I do not link the DLL implicitly (i.e with a *.lib) as the DLL was created by a third party who used the Microsoft compiler whereas I use MinGW. To be noticed that this command is acting on some hardware (advanced camera motorized focus) and thus, must have some pause, delay etc... function to let the HW the time to move.
    Last edited by MattK; 17th April 2012 at 06:54.

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

    Default Re: Preventing a Slot to be called again before it has finished running

    The backtrace you provided doesn't say anywhere the slot was re-entered. I trust the stack more than your "n" variable What does focusCam() do?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


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

    MattK (19th April 2012)

  9. #6
    Join Date
    Mar 2012
    Posts
    16
    Thanks
    15
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Quote Originally Posted by wysota View Post
    The backtrace you provided doesn't say anywhere the slot was re-entered. I trust the stack more than your "n" variable What does focusCam() do?
    I totally agree. I don't see any re-entrancy neither.

    The focusCam() focuses a camera. I gave some details about the function used in focusCam () in the previous post just below the:
    Coming back to the re-entered slot, here is the DLL function called:
    I managed to get a log of:

    bracktrace + thread status + content of most var of the class,

    when n == 0 and then once again when n == 1, from the same execution.

    Both flows in the backtrace are identical, just a very few arguments have changed. This is *extremely* weird I have rarely seen such a thing before. So just n is changing. I'm going to diff the 2 logs and post the log + the diffs here to really see what the differences are between the 2. This could give more clues.

    ps: just discovered wwWidgets, pretty nice! I have to see where I can use those :-)

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

    Default Re: Preventing a Slot to be called again before it has finished running

    I suggest to output two messages to the debugging channel -- one when you enter the function and another one when you return from it. You'll then be able to tell whether you have two "entering" messages in a row without a "leaving" message inbetween.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


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

    MattK (19th April 2012)

  12. #8
    Join Date
    Mar 2012
    Posts
    16
    Thanks
    15
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Quote Originally Posted by wysota View Post
    I suggest to output two messages to the debugging channel -- one when you enter the function and another one when you return from it. You'll then be able to tell whether you have two "entering" messages in a row without a "leaving" message inbetween.
    Good idea.

    So Slot's Code is (I give it in case I did a mistake, we never know):

    Qt Code:
    1. void SelectSource::updateFocusLabel()
    2. {
    3. qDebug() << "Entering: " << __PRETTY_FUNCTION__;
    4.  
    5. n++;
    6. focusCam();
    7. n--;
    8.  
    9. qDebug() << "Quiting " << __PRETTY_FUNCTION__;
    10. }
    To copy to clipboard, switch view to plain text mode 

    Then moving the qSlider with the mouse gives that (5 successive slot calls in this case, one re-entered):

    Qt Code:
    1. Entering: void SelectSource::updateFocusLabel()
    2. Entering: void SelectSource::updateFocusLabel()
    3. Quiting void SelectSource::updateFocusLabel()
    4. Entering: void SelectSource::updateFocusLabel()
    5. Quiting void SelectSource::updateFocusLabel()
    6. Entering: void SelectSource::updateFocusLabel()
    7. Quiting void SelectSource::updateFocusLabel()
    8. Entering: void SelectSource::updateFocusLabel()
    9. Quiting void SelectSource::updateFocusLabel()
    10. Quiting void SelectSource::updateFocusLabel()
    To copy to clipboard, switch view to plain text mode 

    The re-entrance only "happens" (if it realy happens) once, possibly the DLL tries to run its function on the first time which takes say 0.5 second (that's a lot). Then, the DLL detects the same function is called again but since it has not returned from the previous call yet it returns from the next 4 successive calls immediately. This may explain why we do not "re-enter" more than once.

    Now backlog of callstack + threads id + class content and address for the first call (n==0 when entering the slot). The underligned sections represent what changed in the log when we re-entered the slot (s when n==1). Nothing special!

    n == 0, "1st entrance"

    [Name=, displayName=SelectSource::updateFocusLabel(this=0x ea12eb8) at selectsource.cpp:200] C:\\Users\\Matt-usr\\Documents\\CTA\\ProjectFiles\\QtIRView\select source.cpp:200
    [Name=, displayName=SelectSource::qt_metacall(this=0xea12e b8,_c=QMetaObject::InvokeMetaMethod,_id=11,_a=0x22cf58) at moc.tmp/moc_selectsource.cpp:107] C:\\Users\\Matt-usr\\Documents\\CTA\\ProjectFiles\\QtIRView\moc.tm p\moc_selectsource.cpp:107
    [Name=, displayName=QMetaObject::metacall(object=0xea12eb8 ,cl=QMetaObject::InvokeMetaMethod,idx=38,argv=0x22cf58) at kernel\\qmetaobject.cpp:237] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qmetaobject.cpp:237
    [Name=, displayName=QMetaObject::activate(sender=0xea64550 ,m=0x380edc0,local_signal_index=0,argv=0x22cf58) at kernel\\qobject.cpp:3278] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qobject.cpp:3278
    [Name=, displayName=QAbstractSlider::valueChanged(this=0xe a64550,_t1=778) at tmp\\moc\\debug_shared\\moc_qabstractslider.cpp:18 2] C:\Users\Matt-usr\Documents\CTA\bin\tmp\\moc\\debug_shared\\moc_ qabstractslider.cpp:182
    [Name=, displayName=QAbstractSlider::setValue(this=0xea645 50,value=778) at widgets\\qabstractslider.cpp:543] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qabstractslider.cpp :543
    [Name=, displayName=QAbstractSlider::triggerAction(this=0x ea64550,action=QAbstractSlider::SliderMove) at widgets\\qabstractslider.cpp:632] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qabstractslider.cpp :632
    [Name=, displayName=QAbstractSlider::setSliderPosition(thi s=0xea64550,position=778) at widgets\\qabstractslider.cpp:500] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qabstractslider.cpp :500
    [Name=, displayName=QSlider::mouseMoveEvent(this=0xea64550 ,ev=0x22d74c) at widgets\\qslider.cpp:514] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qslider.cpp:514
    [Name=, displayName=QWidget::event(this=0xea64550,event=0x22d74c) at kernel\\qwidget.cpp:8244] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qwidget.cpp:8244
    [Name=, displayName=QAbstractSlider::event(this=0xea64550, e=0x22d74c) at widgets\\qabstractslider.cpp:942] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qabstractslider.cpp :942
    [Name=, displayName=QSlider::event(this=0xea64550,event=0x22d74c) at widgets\\qslider.cpp:435] C:\Users\Matt-usr\Documents\CTA\bin\widgets\\qslider.cpp:435
    [Name=, displayName=QApplicationPrivate::notify_helper(thi s=0xddb3a78,receiver=0xea64550,e=0x22d74c) at kernel\\qapplication.cpp:4462] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication.cpp:446 2
    [Name=, displayName=QApplication::notify(this=0x22ff20,rec eiver=0xea64550,e=0x22d74c) at kernel\\qapplication.cpp:4023] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication.cpp:402 3
    [Name=, displayName=QCoreApplication::notifyInternal(this= 0x22ff20,receiver=0xea64550,event=0x22d74c) at kernel\\qcoreapplication.cpp:731] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qcoreapplication.cpp :731
    [Name=, displayName=QCoreApplication::sendSpontaneousEvent (receiver=0xea64550,event=0x22d74c) at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:218] C:\Users\Matt-usr\Documents\CTA\bin\..\..\include\QtCore\..\..\s rc\corelib\kernel\qcoreapplication.h:218
    [Name=, displayName=QApplicationPrivate::sendMouseEvent(re ceiver=0xea64550,event=0x22d74c,alienWidget=0xea64550,nativeWidget=0x22feb0,butto nDown=0x3a0b41c,lastMouseReceiver=@0x3a0b420: {o = 0xea64550},spontaneous=true) at kernel\\qapplication.cpp:3120] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication.cpp:312 0
    [Name=, displayName=QETWidget::translateMouseEvent(this=0x 22feb0,msg=@0x22dc48: {hwnd = 0x103f8, message = 512, wParam = 1, lParam = 2359687, time = 2284728, pt = {x = 391, y = 58}}) at kernel\\qapplication_win.cpp:3321] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication_win.cpp :3321
    [Name=, displayName=QtWndProc@16(hwnd=0x103f8,message=512, wParam=1,lParam=2359687) at kernel\\qapplication_win.cpp:1659] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication_win.cpp :1659
    [Name=, displayName=USER32!IsWindowVisible()] C:\\Windows\\system32\\user32.dll
    [Name=, displayName=Address: [@0x000103f8]]
    [Name=, displayName=Address: [@0x00000200]]
    [Name=, displayName=USER32!IsWindowVisible()] C:\\Windows\\system32\\user32.dll
    [Name=, displayName=qt_is_translatable_mouse_event(message =0) at kernel\\qapplication_win.cpp:1426] C:\Users\Matt-usr\Documents\CTA\bin\kernel\\qapplication_win.cpp :1426
    [Name=, displayName=USER32!IsWindowVisible()] C:\\Windows\\system32\\user32.dll
    [Name=, displayName=Address: [@0x00000000]]

    [Name=, displayName=12 thread 5884.0x17b4 0x77697094 in ntdll!LdrFindResourceEx_U ()]
    [Name=, displayName=11 thread 5884.0x17ec 0x77697094 in ntdll!LdrFindResourceEx_U ()]
    [Name=, displayName=10 thread 5884.0x17d8 0x77697094 in ntdll!LdrFindResourceEx_U ()]
    [Name=, displayName=6 thread 5884.0x17a4 0x77697094 in ntdll!LdrFindResourceEx_U ()]
    [Name=, displayName=5 thread 5884.0x1780 0x77697094 in ntdll!LdrFindResourceEx_U ()]
    [Name=, displayName=4 thread 5884.0x174c 0x77697094 in ntdll!LdrFindResourceEx_U ()]
    [Name=, displayName=3 thread 5884.0x177c 0x77697094 in ntdll!LdrFindResourceEx_U ()]
    [Name=, displayName=2 thread 5884.0x1778 0x77697094 in ntdll!LdrFindResourceEx_U ()]
    [Name=, displayName=1 thread 5884.0x16f8 SelectSource::updateFocusLabel (this=0xea12eb8) at selectsource.cpp:200]

    [Name=, displayName=this] class SelectSource * const 0xea12eb8
    [Name=, displayName=<Base class>] QWidget {<QObject> = {_vptr.QObject = 0x469688, static staticMetaObject = {d = {superdata = 0x0, stringdata = 0xcfb0a0 "QObject", data = 0xcfafe0, extradata = 0xcfb12c}}, d_ptr = {d = 0xea12f30}, static staticQtMetaObject = {d = {superdata = 0x0, stringdata = 0xd0c700 "Qt", data = 0xd0a160, extradata = 0x0}}}, <QPaintDevice> = {_vptr.QPaintDevice = 0x469770, painters = 0}, static staticMetaObject = {d = {superdata = 0xcfae08, stringdata = 0x3789120 "QWidget", data = 0x3788c60, extradata = 0x0}}, data = 0xea12fe8}
    [Name=, displayName=ResEnhanAct] class QAction * 0xea55018
    [Name=, displayName=autoFocusAct] class QAction * 0xea5b9b8
    [Name=, displayName=connectCamAct] class QAction * 0xea15018
    [Name=, displayName=filesAreTheSource] class QAction * 0xbaadf00d
    [Name=, displayName=getRingElement] class GetRingElement * 0xea66a48
    [Name=, displayName=n] int 0
    [Name=, displayName=nucAct] class QAction * 0xea568b8
    [Name=, displayName=pauseAct] class QAction * 0xea14e00
    [Name=, displayName=qLabelFocus] class QLabel * 0xea641c0
    [Name=, displayName=qLineEditCommand] class QLineEdit * 0xea601d8
    [Name=, displayName=qSliderFocus] class QSlider * 0xea64550
    [Name=, displayName=reDialog] class REDialog * 0xea56228
    [Name=, displayName=reinitAct] class QAction * 0xea5b470
    [Name=, displayName=sendCommandToCam] SendCommandToCam {<No data fields>}
    [Name=, displayName=sourceMenu] class QMenu * 0xea0b930
    [Name=, displayName=sourceToolBar] class QToolBar * 0xea5bac8
    [Name=, displayName=spawnNewViewAct] class QAction * 0xea13200
    [Name=, displayName=staticMetaObject] {d = {superdata = 0x37766ac, stringdata = 0x42f1c0 "SelectSource", data = 0x42f040, extradata = 0x0}}
    [Name=, displayName=vc] VarioCam * 0xea13118

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

    Default Re: Preventing a Slot to be called again before it has finished running

    If you remove all the dll calls from your code, do you still get the same behaviour?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


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

    MattK (19th April 2012)

  15. #10
    Join Date
    Mar 2012
    Posts
    16
    Thanks
    15
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Quote Originally Posted by wysota View Post
    If you remove all the dll calls from your code, do you still get the same behaviour?
    No, not at all. I forgot to mention that. Only the DLL seems to create this mess.

    I though maybe the time needed to run the slot was an issue as the call to the dll may take up to 1 sec to complete, but it's not that. To be sure, if I remove the call to the dll, and replaced it by a for(int i=0, i<j; i++); with j large enough to create a 1 sec delay. In this case the slot runs exactly as expected: no re-entrency and the widget GUI lags because it can't move faster than the slot can run (which is good, so the GUi stay well synch with the code).

    I'm gonna try some stuff with the queued mode of the connection. Maybe Qt is fooled with the DLL and thinks it is a separated thread, in which case it may force (implicitely?) a queued connect instead of a normal direct connect? Still, even a queued connect should not allow the slot to be re-entered.

  16. #11
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: Preventing a Slot to be called again before it has finished running

    Unless the DLL does something that will trigger a signal that is connected to this slot I do not see how you get multiple calls. Does the DLL cause a resize of the window or change of data associated with qSliderFocus, triggering slider has to change value?

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

    MattK (19th April 2012)

  18. #12
    Join Date
    Mar 2012
    Posts
    16
    Thanks
    15
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Quote Originally Posted by ChrisW67 View Post
    Unless the DLL does something that will trigger a signal that is connected to this slot I do not see how you get multiple calls. Does the DLL cause a resize of the window or change of data associated with qSliderFocus, triggering slider has to change value?
    Thanks for the suggestion (I'll take anything since I ran out of idea). The DLL is part of a driver interfacing a scientific thermal infrared camera. It doesn't use/create any GUI. It's very basic. The DLL does not know my Qt application as the DLL was written by a 3rd party firm 5 years ago. The DLL as used in the Qt application takes a string that is a focus command. Then, the DLL gives a message back as a string. I read the string and throw this string into a custom Widget based console. This makes me think I must isolate the DLL call from anything else by not recovering the DLL's answer to see if the Slot still behave this way.

    So:

    1 - a slot can't be re-entered by the same widget's signal
    2 - the call stack confirms the slot is not re-entered, in the case of 2 and 3 below.
    3 - in practice the slot is (like) re-entered. A re-entrency counter (n) shows it.
    4 - A qDebug message in the slot gave again the evidence the slot was (like) re-entered.

    So we still have 2 very simple evidences (1,2) vs 2 opposite simple evidences (3,4). Interesting... what can cause such a thing?

    Forgot to say this happens in both release and debug mode, so it's not a magical preemptive optimization trick that GCC did neither.

  19. #13
    Join Date
    Mar 2008
    Location
    Kraków, Poland
    Posts
    1,536
    Thanked 284 Times in 279 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Maybe the DLL is calling QCoreApplication::processEvents.

  20. The following user says thank you to Lesiok for this useful post:

    MattK (20th April 2012)

  21. #14
    Join Date
    Sep 2011
    Posts
    1,241
    Thanks
    3
    Thanked 127 Times in 126 Posts
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    print thread id next to your enter/quit statements.

    also put try/catch around dll call (and print exception if there is one).
    If you have a problem, CUT and PASTE your code. Do not retype or simplify it. Give a COMPLETE and COMPILABLE example of your problem. Otherwise we are all guessing the problem from a fabrication where relevant details are often missing.

  22. The following user says thank you to amleto for this useful post:

    MattK (20th April 2012)

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

    Default Re: Preventing a Slot to be called again before it has finished running

    Does the DLL link to Qt? Does it use Qt? Does it use callbacks into your own code? If no then there is simply no way it can influence the way the slot is called, regardless if it uses threads or not.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


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

    MattK (20th April 2012)

  25. #16
    Join Date
    Mar 2012
    Posts
    16
    Thanks
    15
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Thx all for support again.

    Answering to everybody in a single post with citation.


    Quote Originally Posted by MattK View Post
    This makes me think I must isolate the DLL call from anything else by not recovering the DLL's answer to see if the Slot still behave this way.
    I answer to myself here: isolating the DLL call in the slot, so the slot only calls the dll (the answer is not recoreved and not sent into the console widget) doesn't change anything.
    I also tried to change the Qt::ConnectionType in the connect() to force it to queued or direct. This doesn't change anything.

    Quote Originally Posted by Lesiok View Post
    Maybe the DLL is calling QCoreApplication::processEvents.
    I wished it was this, but no. See post #12 for more about the DLL.

    Quote Originally Posted by amleto View Post
    print thread id next to your enter/quit statements.

    also put try/catch around dll call (and print exception if there is one).

    In post #8 we see that only 1 thread is running. I have followed your idea anyway in case this helps to see something new we may have missed. We never know...

    I'm publishing the code in case I did a mistake in the code:

    Qt Code:
    1. void SelectSource::createToolbar()
    2. {
    3. ...
    4. connect(qSliderFocus, SIGNAL(valueChanged(int)), this, SLOT(updateFocusLabel()));
    5. ...
    6. }
    7.  
    8. void SelectSource::updateFocusLabel()
    9. {
    10. qDebug() << "Entering: " << __PRETTY_FUNCTION__ << " Thread ID: " << QThread::currentThreadId();
    11.  
    12. n++;
    13. char answer[5000];
    14. vc_operate_command(vc->Vcam.Handle, ":focsteps 200,120", answer, 5000); // This is the DLL call that was buried in a local function "focusCam()" before.
    15. n--;
    16.  
    17. qDebug() << "Quiting " << __PRETTY_FUNCTION__ << " Thread ID: " << QThread::currentThreadId();
    18. }
    To copy to clipboard, switch view to plain text mode 

    Which gives:

    Qt Code:
    1. Entering: void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    2. Entering: void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    3. Quiting void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    4. Entering: void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    5. Quiting void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    6. Entering: void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    7. Quiting void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    8. Quiting void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    9. Entering: void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    10. Entering: void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    11. Quiting void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    12. Quiting void SelectSource::updateFocusLabel() Thread ID: 0x11a8
    To copy to clipboard, switch view to plain text mode 

    Now, with a try/catch, I used this:

    Qt Code:
    1. void SelectSource::updateFocusLabel()
    2. {
    3. qDebug() << "Entering: " << __PRETTY_FUNCTION__ << " Thread ID: " << QThread::currentThreadId();
    4. n++;
    5. try{
    6. char answer[5000];
    7. vc_operate_command(vc->Vcam.Handle, ":focsteps 200,120", answer, 5000); // #include "vc2dll.h"
    8. }
    9. catch (...) // we catch any potential exception of any type.
    10. {
    11. qDebug() << "Some exception happened";
    12. }
    13. n--;
    14. qDebug() << "Quiting " << __PRETTY_FUNCTION__ << " Thread ID: " << QThread::currentThreadId();
    15. }
    To copy to clipboard, switch view to plain text mode 

    This doesn't not give any exception (but is the try catch code even correct? I'm not used to use try/catch statements in my code)

    Quote Originally Posted by wysota View Post
    Does the DLL link to Qt? Does it use Qt? Does it use callbacks into your own code? If no then there is simply no way it can influence the way the slot is called, regardless if it uses threads or not.
    >the DLL link to Qt?
    No
    >Does it use Qt?
    No
    >Does it use callbacks into your own code?
    No.
    See msg #12 for more on DLL. The dll call is basically a black bo that does some stuffs (fcusing a camera). I call it as an ordinary and normal C function that has no link to Qt and no special link to my Qt code.

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

    Default Re: Preventing a Slot to be called again before it has finished running

    If you do get a double call then the only explanation I can see is that the DLL corrupts the stack somehow. I suggest you place a breakpoint on the dll function and step through execution of the code to see if it ends up calling the slot again.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


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

    MattK (27th April 2012)

  28. #18
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    If you do get a double call then the only explanation I can see is that the DLL corrupts the stack somehow. I suggest you place a breakpoint on the dll function and step through execution of the code to see if it ends up calling the slot again.
    After reading through, that is my conclusion as well. The "reentrancy" you are seeing is just an artifact of stack corruption.

    Does the DLL expect arguments to the function you are calling (but maybe not providing)? Are your arguments of the same type expected by the DLL? If you are passing in a pointer to some buffer, is the buffer big enough? What happens if you change the size of buffers / arrays / whatever that are used by the DLL? Using global variables shared between the app and DLL? What happens if you rearrange them?

  29. The following user says thank you to d_stranz for this useful post:

    MattK (27th April 2012)

  30. #19
    Join Date
    Mar 2012
    Posts
    16
    Thanks
    15
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Preventing a Slot to be called again before it has finished running

    Quote Originally Posted by wysota View Post
    If you do get a double call then the only explanation I can see is that the DLL corrupts the stack somehow. I suggest you place a breakpoint on the dll function and step through execution of the code to see if it ends up calling the slot again.
    Quote Originally Posted by d_stranz View Post
    After reading through, that is my conclusion as well. The "reentrancy" you are seeing is just an artifact of stack corruption.

    Does the DLL expect arguments to the function you are calling (but maybe not providing)? Are your arguments of the same type expected by the DLL? If you are passing in a pointer to some buffer, is the buffer big enough? What happens if you change the size of buffers / arrays / whatever that are used by the DLL? Using global variables shared between the app and DLL? What happens if you rearrange them?
    @both: The Slot is really called twice as shown by the qDebug or re-entrancy counter, but we do not see that on the stack. So I agree your theory of a corrupted stack makes a lot of sense. What's interesting is that it doesn't crash, and it really works as it should if re-entrancy was possible or as if this behavior was done on purpose.

    @wysota: I can't debug while it is stacking because for this bug to happen the slot must be called twice fastly. The 2nd call must happens as the DLL call hasn't returned. But I can easily place a break point as the 2nd call is unstacked (returned) and see when the slot is re-entered to be unstacked (finished) from the 1st call.

    @d_stranz: Thanks for suggestions. I'll try all that and publish the results here.

    In the meantime I wrote a Slot that can handle re-entrancy with a queue. It works like a charm as expected. The Slot basically queues the arguments it receives and then reorders them in the right order: because of the recursive nature of re-entrency, slot's arguments are stacked as a FILO, so the last arguments received by the slot from the last are used first. But I want them to be used last instead like the slot were called "normally" without re-entrancy. So the queue in the Slot is read as a FIFO. Here is the code (seems very simple to follow, but it's not as it's a hack that counters an abnormal behavior):

    Qt Code:
    1. struct QUEUE
    2. {
    3. // Queue for focus action
    4. int idx;
    5. int val[2];
    6. };
    7.  
    8. QUEUE queue; // in header
    9.  
    10. queue.idx = 0; // in class constructor
    11.  
    12. void SelectSource::focusCam() // Slot connected to the qSlider:
    13. {
    14. // This queue can have 2 items (camera commands) at most.
    15. // If adding new items as the queue is full, the last item is replaced with the new one.
    16. // This is because we can't replace the first item as it was sent to sendCommandToCam.msg()
    17. // already and because the 2nd item has got obsolete because of the new one.
    18.  
    19. // This function also convert the FILO behavior resulting from recursive slot re-entrancy
    20. // calls into a normal FIFO so that future events do not happen first anymore.
    21.  
    22. // It can be difficult to follow this code because of the very unusual flow of Qt.
    23. // The best is to start an example with 1 item added, then add another
    24. // item while in call of sendCommandToCam.msg(&vc->Vcam, cmd); (assume this one takes a
    25. // long time to return and that this slot keeps being called in the meantime with new values)
    26.  
    27. queue.val[(queue.idx==2)?1:queue.idx] = qSliderFocus->value();
    28.  
    29. if(queue.idx==2)
    30. return;
    31.  
    32. queue.idx++;
    33.  
    34. if(queue.idx==2)
    35. return;
    36.  
    37. do
    38. { // this loop can be only reached the first time this slot is called.
    39. QString cmd;
    40. cmd = QString(":focsteps %1,120").arg(queue.val[0],0,10);
    41. sendCommandToCam.msg(&vc->Vcam, cmd); // Slot can be re-entered as this function runs for an unknown reason. Contains a DLL call.
    42. queue.val[0] = queue.val[1];
    43. } while (--queue.idx);
    44. }
    To copy to clipboard, switch view to plain text mode 

  31. #20
    Join Date
    Mar 2009
    Location
    Brisbane, Australia
    Posts
    7,729
    Thanks
    13
    Thanked 1,610 Times in 1,537 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows
    Wiki edits
    17

    Default Re: Preventing a Slot to be called again before it has finished running

    Random thought: could this be the result of calling the DLL function using the wrong parameter passing arrangement, i.e. stdcall vs. cdecl ? If the called function clears the stack (and shouldn't) then the caller clears the stack again...
    http://stackoverflow.com/questions/3...call-and-cdecl

  32. The following 2 users say thank you to ChrisW67 for this useful post:

    d_stranz (26th April 2012), MattK (27th April 2012)

Similar Threads

  1. Replies: 2
    Last Post: 26th August 2011, 08:51
  2. Replies: 3
    Last Post: 13th July 2011, 08:24
  3. Replies: 3
    Last Post: 7th April 2011, 11:09
  4. QProcess finished slot not firing
    By doggrant in forum Qt Programming
    Replies: 0
    Last Post: 10th November 2010, 13:09
  5. Replies: 0
    Last Post: 24th May 2010, 08:11

Tags for this Thread

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.