Results 1 to 12 of 12

Thread: How to disconnect signal/slot?

  1. #1
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default How to disconnect signal/slot?

    Hi everyone. I'm using a third party library in my app written in C, which uses a lot of printf statements. I wanted to redirect that prints to a textEdit on my app. So with the help of others I wrote a redirection function, which redirects stdout to a file and adds text to my textEdit whenever content of file changes. So far so good everything works ok. However at the end external lib call I would like to quit that redirection and delete the file as well, but when I do so I get an error that redirection file does not exist anymore. This would probably mean that signal/slot connection still exists. How can I fix this? Much thanks for help in advance. The code looks like this:
    Qt Code:
    1. void MainWindow::RedirectOutput(int type) {
    2. QFileSystemWatcher * watcher = new QFileSystemWatcher(this);
    3. if (type==0) {
    4. // redirect stdout to file
    5. freopen("redirect.txt","w",stdout);
    6.  
    7. // disable buffering
    8. setvbuf(stdout,NULL,_IONBF,0);
    9.  
    10. // check if file changed
    11.  
    12. watcher->addPath("redirect.txt");
    13. connect(watcher,SIGNAL(fileChanged(QString)),this,SLOT(HandleFileChange(QString)));
    14. } else {
    15. // reenable buffering, not really needed
    16. //setvbuf(stdout,NULL,_IOFBF,4000);
    17.  
    18. //return stdout to display
    19. freopen( "CON","w",stdout);
    20. disconnect(watcher,SIGNAL(fileChanged(QString)),this,SLOT(HandleFileChange(QString))); //<doesnt' work
    21. if (QFile::exists("redirect.txt"))
    22. QFile::remove("redirect.txt");
    23. }
    24. }
    25.  
    26. void MainWindow::HandleFileChange(const QString filename){
    27. QFile f(filename);
    28. if (f.open(QIODevice::ReadOnly)) {
    29. //QMessageBox::information(this,"info",QString::number(f.size()));
    30. f.seek(fbytes);
    31. const QByteArray ba = f.readAll();
    32. fbytes += ba.size();
    33. //QMessageBox::information(this,"stdout",filename + " changed:\n\n" + ba);
    34. //cout << qPrintable(ba) << endl;
    35. ui->textEdit->append(qPrintable(ba));
    36. } else {
    37. QMessageBox::critical(this,"stdout","Can't open file");
    38. }
    39. }
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Oct 2009
    Posts
    483
    Thanked 97 Times in 94 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to disconnect signal/slot?

    I suspect that the fact that the file exists or not has nothing to do with the connection. You claim that things do not work as expected. Here are a few hints:
    • have you run a debugger?
    • what are the return values of the functions that potentially fail (freopen, disconnect, etc.)?
    • have you actually seen the file being created?
    • have you actually seen the file grow bigger?

  3. #3
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to disconnect signal/slot?

    Your disconnect looks correct.

    Alternative disconnect() options are:

    - delete either sender or receiver, in your case probably the sender
    - call disconnect() on the sender to disconnect all receivers
    - call disconnect with 0 for slot and signal but provide sender and receiver to disconnect a certain receiver
    - (Qt5 onwards) store the result of the connect and use this QMetaObject::Connection value as an argument to QObject::disconnect()

    Cheers,
    _

  4. #4
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to disconnect signal/slot?

    Thank you both for suggestions. It was my fault, I called function RedirectOutput with 0 at the beginning and RedirectOutput with 1 at the end of external library call, but this way I had different "watcher" created 2 times.
    Qt Code:
    1. QFileSystemWatcher * watcher = new QFileSystemWatcher(this);
    To copy to clipboard, switch view to plain text mode 
    I solved this, so the signal-slot gets disconnected, but now I have a bigger problem. It looks like the external lib function call executes so fast that signals don't fire in time, or the thing runs asynchronously. So it looks like, I disconnect signal-slot before the signals arrive. I figured out this by adding some custom marks to my textEdit and watched the sequence how they got appended. Here is some pseudo code
    Qt Code:
    1. put redirect to file & connect signal-slot
    2. execute external lib code
    3. get output back to screen and disconnect signal-slot
    To copy to clipboard, switch view to plain text mode 
    I can post entire code if necessary. Do you have any suggestion how could I solve this. I'm banging my head against the wall the entire afternoon with this, so any idea much appreciated.

  5. #5
    Join Date
    Oct 2009
    Posts
    483
    Thanked 97 Times in 94 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to disconnect signal/slot?

    You cannot rely on QFileSystemWatcher to keep you informed of all changes to the file in a timely manner. With your current architecture, perhaps you should inspect the file one last time before you delete it, and catch any output not reported by the watcher.

    There are alternatives, but I am afraid they are platform-specific.

    Under a POSIX system, you can call open_memstream() to open a growable memory stream and try to assign the resulting stream to stdin (but that may not work as stdin is not guaranteed to be assignable), but you will need to poll the stream regularly to get its contents.

    Alternatively, you may use pipe() and dup2() to redirect the underlying stdout file descriptor to a pipe, and use QSocketNotifier to get notifications whenever data arrives in the pipe. Beware of deadlocks though: printf() in the library will block whenever the pipe's buffer is full, so it is vital that the QSocketNotifier live in another thread whose job is to:
    1. quickly read from the pipe,
    2. decode the bytes with a stateful decoder (QTextDecoder) into a growable QString,
    3. emit a signal to notify the GUI thread that data is available,
    4. NEVER write anything to stdout!

    When the main GUI returns to its event loop and picks up the signal, it can consume the contents of the QString and append them to the display widget.

    I see no way around the asynchrony of these solutions: you have no way to execute arbitrary code (like appending text to a display widget) in the middle of a printf() call by the library. Arguably it would be much easier if your library lived in another process or had alternative ways to log its output.

  6. #6
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to disconnect signal/slot?

    thanks yeye_olive, the solution you describe looks a bit complicated for my current level of knowledge in c++ and qt, however the idea of having a second thread for invoking external lib would probably be simpler or at least better, I've done something like that once in Java, but I have to refresh/check how the principle how that works. One question though: if I redirect display of stdout to file in second thread, do I still have normal stdout in first (main) thread? Much thanks again.

  7. #7
    Join Date
    Oct 2009
    Posts
    483
    Thanked 97 Times in 94 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to disconnect signal/slot?

    Quote Originally Posted by arcull View Post
    thanks yeye_olive, the solution you describe looks a bit complicated for my current level of knowledge in c++ and qt, however the idea of having a second thread for invoking external lib would probably be simpler or at least better, I've done something like that once in Java, but I have to refresh/check how the principle how that works.
    Actually the solution I outlined in my previous post assumed that the library calls were executed in the main (GUI) thread; the other thread is only needed to read from the pipe while the library writes to it through stdout. The thread does not even need to be visible outside of the logging mechanism.

    Quote Originally Posted by arcull View Post
    if I redirect display of stdout to file in second thread, do I still have normal stdout in first (main) thread?
    Unfortunately, the answer is no. stdout is a process-wide stream. It would be great if the library were able to write to a custom logger instead of stdout; you could then implement a logger that would append the text to your widget. If you need a separate stdout for the rest of your program, then I am afraid your only option is to spawn a process that will execute the library calls on your behalf.

  8. #8
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to disconnect signal/slot?

    thanks yeye_olive. Well I have to consider how much gain do I get with how much trouble. The point is that the external lib uses pritfs when you invoke it's functions and since I have a gui app, I could leave the stdout redirection to file active the whole time, just for the purpose of external lib. If I want to print out something to the qui interface like textEdit, I don't really need printfs. I mean I can avoid the print to stdout from my main app, I can use textEdit->append and similar methods. Or am I missing something here? Thanks for your help.

  9. #9
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to disconnect signal/slot?

    Depending on what kind of data you need to transfer between your code and the library, one option could be to run the library in a helper program through QProcess.

    Cheers,
    _

  10. #10
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to disconnect signal/slot?

    thanks anda_skoa, but I'm not sure I understand what you mean by QProcess. Is this second thread approach? Please provide more info and how to intercept library string output this way? Type of data the library outputs is more or less just some strings explaining progress and results nothing more. Thanks.

  11. #11
    Join Date
    Jan 2006
    Location
    Graz, Austria
    Posts
    8,416
    Thanks
    37
    Thanked 1,544 Times in 1,494 Posts
    Qt products
    Qt3 Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to disconnect signal/slot?

    Not a thread, a separate process.

    QProcess is Qt's facility for running other programs, it can write to the other programs stdin and read its stdout and stderr.

    Depending on the data to the library it might be possible to create a small helper program that is run by the main application as a child process.

    Cheers,
    _

  12. #12
    Join Date
    Oct 2013
    Posts
    102
    Thanked 1 Time in 1 Post
    Qt products
    Qt5
    Platforms
    Unix/X11 Windows

    Default Re: How to disconnect signal/slot?

    I've been tackling this issue a bit more and came to a conclusion, that in my case it is better not to use signal/slots at all. I've done it this way: whenever I need to call the external lib functions I first invoke my function which redirects stdout to a file, then call the function and afterwards call another my function which set stdout to normal, reads content of the redirection file and appends it to my textEdit. Thank you again all for you suggestions.

Similar Threads

  1. QML 1 problem with signal disconnect
    By nick85 in forum Qt Quick
    Replies: 0
    Last Post: 19th December 2013, 10:24
  2. qxtsmtp connect->disconnect
    By bloodfont in forum Qt Programming
    Replies: 0
    Last Post: 11th June 2013, 13:48
  3. waitForReadyRead and disconnect
    By matteo.ceruti in forum Qt Programming
    Replies: 6
    Last Post: 27th November 2012, 19:28
  4. disconnect usb device
    By marco.stanzani in forum Qt Programming
    Replies: 1
    Last Post: 4th November 2011, 19:42
  5. disconnect SIGNAL/SLOT directly after emitting data
    By donglebob in forum Qt Programming
    Replies: 1
    Last Post: 4th February 2009, 22:53

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.