Results 1 to 9 of 9

Thread: Seeking design advise - part 1

  1. #1
    Join Date
    Nov 2009
    Location
    US, Midwest
    Posts
    215
    Thanks
    62
    Thanked 4 Times in 4 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Seeking design advise - part 1

    This is the development based on my question here

    My problem now is that I can't get the signal directoryChanged of the class QFileSystemWatcher to work with the slot in the thread where QFileSystemWatcher is created. Following is the code:
    Any help with getting it to work correctly (catch the signal) will be greatly appreciated.
    Thanks!

    Qt Code:
    1. class threadedScraper : public QThread
    2. {
    3. Q_OBJECT
    4. int _id;
    5. QMutex& _mtx;
    6. QString _path;
    7. QFileSystemWatcher* _filesystemwatcher;
    8. void run() override
    9. {
    10. _filesystemwatcher = new QFileSystemWatcher();
    11. _filesystemwatcher->moveToThread(this);
    12. _filesystemwatcher->addPath(_path);
    13.  
    14. // I tried different connection types. Qt::ConnectionType::DirectConnection does not work either
    15. if (! connect(_filesystemwatcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(ondirectoryChanged(const QString&))))
    16. {
    17. qDebug() << "failure to connect to QFileSystemWatcher::directoryChanged signal";
    18. return;
    19. }
    20.  
    21. qDebug() << QString("cycle %1: waiting for file creation in %2").arg(_id).arg(_path);
    22. exec();
    23. qDebug() << QString("cycle %1: stopped waiting for file").arg(_id);
    24. }
    25. private slots:
    26. void ondirectoryChanged (const QString& p)
    27. {
    28. qDebug() << "cycle:" << QString::number(_id) << "file:" <<p;
    29. _mtx.unlock();
    30. }
    31. public:
    32. threadedScraper(int id, QMutex& m, QString p) : _id(id), _mtx(m), _path(p), _filesystemwatcher(nullptr), QThread()
    33. {
    34. }
    35. virtual ~threadedScraper()
    36. {
    37. if (_filesystemwatcher != nullptr)
    38. delete _filesystemwatcher;
    39. }
    40. };
    41.  
    42. int main(int argc, char *argv[])
    43. {
    44. QCoreApplication a(argc, argv);
    45.  
    46. QMutex mtx;
    47. QString directoryToMonitor="c:/temp/files";
    48.  
    49. QTimer::singleShot(2000,&a, [&](){
    50. qDebug()<< "started scraping";
    51. for (int i = 0; i < 2; ++i) {
    52. qDebug() << "starting cycle " << QString::number(i);
    53. threadedScraper worker (i, mtx, directoryToMonitor);
    54. worker.start();
    55. mtx.lock();
    56. wc.wait(&mtx, 5000); // I need to wait until the file is found in the monitoring directory or 5 seconds elapsed
    57. worker.exit(0); // stop the thread
    58. worker.wait();
    59. mtx.unlock();
    60. }
    61. qDebug()<< "finished scraping";
    62. });
    63. return a.exec();
    64. }
    To copy to clipboard, switch view to plain text mode 

  2. #2
    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: Seeking design advise - part 1

    My problem now is that I can't get the signal directoryChanged of the class QFileSystemWatcher to work
    What about other signals? Do they work?
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. #3
    Join Date
    Nov 2009
    Location
    US, Midwest
    Posts
    215
    Thanks
    62
    Thanked 4 Times in 4 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Seeking design advise - part 1

    I don't know, I only used this one, directoryChanged. I don't think that it is the issue with signal firing, I am pretty sure that all this signals work. I think that somehow the qFileSystemWatcher instance still "lives" in the main thread and not in the thread where I am creating it and moving it into.
    the code is compilable, if you have 5 mins you can run it, or I can post the project here, it is tiny.

  4. #4
    Join Date
    Nov 2009
    Location
    US, Midwest
    Posts
    215
    Thanks
    62
    Thanked 4 Times in 4 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Seeking design advise - part 1

    Problem solved. Thanks.

  5. #5
    Join Date
    Jul 2008
    Location
    Germany
    Posts
    503
    Thanks
    11
    Thanked 76 Times in 74 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: Seeking design advise - part 1

    It would be nice to tell us how you solved your problem.

    Ginsengelf

  6. #6
    Join Date
    Nov 2009
    Location
    US, Midwest
    Posts
    215
    Thanks
    62
    Thanked 4 Times in 4 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Seeking design advise - part 1

    I did not solve the issue with the code that I posted. I rewrote the code, following is the version that works:


    Qt Code:
    1. class scraperProcess: public QObject, public QRunnable
    2. {
    3. Q_OBJECT
    4. QMutex& _mtx;
    5. QWaitCondition& _wc;
    6. public:
    7. scraperProcess(QMutex& mtx, QWaitCondition& w) : _mtx(mtx), _wc(w){}
    8. void run()
    9. {
    10. qDebug()<< "started scraping";
    11. for (int i = 0; i < 3; ++i) {
    12. qDebug() << "cycle starts: " << QString::number(i);
    13. _mtx.lock();
    14. _wc.wait(&_mtx, 5000); // I need to wait until the file is found in the monitoring directory or 5 seconds elapse
    15. _mtx.unlock();
    16. qDebug() << "cycle ends: " << QString::number(i);
    17. }
    18. qDebug()<< "finished scraping";
    19. emit onFinish();
    20. }
    21. signals:
    22. void onFinish();
    23. };
    24.  
    25.  
    26. int main(int argc, char *argv[])
    27. {
    28. QCoreApplication a(argc, argv);
    29.  
    30. QMutex mtx;
    31. QFileSystemWatcher _filesystemwatcher;
    32. QString directoryToMonitor="c:/temp/files";
    33. _filesystemwatcher.addPath(directoryToMonitor);
    34. if (! QObject::connect(&_filesystemwatcher, &QFileSystemWatcher::directoryChanged, [&](const QString& p){
    35. qDebug() << "scraped file:" <<p;
    36. wc.wakeAll();
    37. })) {
    38. qDebug() << "failure to connect to QFileSystemWatcher::directoryChanged signal";
    39. }
    40.  
    41. scraperProcess* ms = new scraperProcess(mtx, wc);
    42. QObject::connect(ms, &scraperProcess::onFinish, [&](){
    43. _filesystemwatcher.removePath(directoryToMonitor);
    44. });
    45.  
    46. QTimer::singleShot(2000,&a, [&](){
    47. QThreadPool::globalInstance()->start(ms);
    48. });
    49.  
    50. return a.exec();
    51. }
    To copy to clipboard, switch view to plain text mode 

    I think I have an idea what might be the problem with the previous versions. It is "singleShot". This is essentially a wrapper for handling the event in the event loop. My previous code was "sitting" in it, preventing other events from being processed. That's my theory.

    I always wonder how to start something in the console application. The "singleShot" is what comes to mind first. Perhaps, posting an event. I'd like to see the "proper" way of doing this.

    Thanks to everyone who read and/or post comments.

  7. #7
    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: Seeking design advise - part 1

    Quote Originally Posted by TorAn View Post
    Qt Code:
    1. void run() override
    2. {
    3. _filesystemwatcher = new QFileSystemWatcher();
    4. _filesystemwatcher->moveToThread(this);
    To copy to clipboard, switch view to plain text mode 
    moveToThread() is not necessary, the QFileSystemWatcher object is created in run(), thus by the secondary thread.

    Quote Originally Posted by TorAn View Post
    Qt Code:
    1. // I tried different connection types. Qt::ConnectionType::DirectConnection does not work either
    2. if (! connect(_filesystemwatcher, SIGNAL(directoryChanged(const QString&)), this, SLOT(ondirectoryChanged(const QString&))))
    To copy to clipboard, switch view to plain text mode 
    Be aware that ondirectoryChanged() will be executed on the main thread, i.e. the thread that created the threadedScraper object.
    I.e. AutoConnection behaves like QueuedConnection if the emitting thread and the receiver object's thread are not the same.

    Quote Originally Posted by TorAn View Post
    Qt Code:
    1. virtual ~threadedScraper()
    2. {
    3. if (_filesystemwatcher != nullptr)
    4. delete _filesystemwatcher;
    5. }
    To copy to clipboard, switch view to plain text mode 
    The _filesystemwatcher object got created in run(), by the secondary thread, so it should be deleted by that thread.
    E.g. at the end of run().

    Quote Originally Posted by TorAn View Post
    Qt Code:
    1. wc.wait(&mtx, 5000); // I need to wait until the file is found in the monitoring directory or 5 seconds elapsed
    To copy to clipboard, switch view to plain text mode 
    You always wait for 5 seconds because the other thread has no access to the wait condition and can't wake the main thread.

    Not really sure why you need such a complicated multi thread setup if you don't do any work in the primary thread anyway.

    Quote Originally Posted by TorAn View Post
    My previous code was "sitting" in it, preventing other events from being processed. That's my theory.
    Yes, because your original code blocked the main thread in a wait condition.

    Quote Originally Posted by TorAn View Post
    The "singleShot" is what comes to mind first.
    If there is no external trigger than this is a good solution.

    In this case unnecessary as you have an external trigger: the file system watcher.

    Cheers,
    _

  8. #8
    Join Date
    Nov 2009
    Location
    US, Midwest
    Posts
    215
    Thanks
    62
    Thanked 4 Times in 4 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Seeking design advise - part 1

    anda_skoa - thank you for your responses.

    You wrote:
    Be aware that ondirectoryChanged() will be executed on the main thread, i.e. the thread that created the threadedScraper object.
    Can you explain why? The instance of fileSystemWatcher is created in run method of threadedScraper instance, so why would ondirectoryChanged slot be executed in the context of the main thread and not in the event loop of the threadedScraper?

    Thank you again for answering!

  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: Seeking design advise - part 1

    Quote Originally Posted by TorAn View Post
    Can you explain why?
    Certainly

    Quote Originally Posted by TorAn View Post
    The instance of fileSystemWatcher is created in run method of threadedScraper instance, so why would ondirectoryChanged slot be executed in the context of the main thread and not in the event loop of the threadedScraper?
    The connect() uses four arguments, meaning the fifth argument is the default value Qt::AutoConnection

    For AutoConnection the emitting thread checks if it is the same thread as the one which "owns" the receiver object.
    If it is, then it will behave like in a DirectConnection, it will call the slot directly.
    If it is not, then it will behave like in a QueuedConnection, it will send a method invocation event to the receiver object's thread.

    Here the emitting thread is the secondary thread, the "owner" of the receiver object "worker" is the main thread.
    So case 2, behavior like a QueuedConnection.

    Cheers,
    _

Similar Threads

  1. Seeking design advise
    By TorAn in forum Qt Programming
    Replies: 8
    Last Post: 9th March 2019, 10:46
  2. Reading text file line part by part
    By anh5kor in forum Newbie
    Replies: 4
    Last Post: 23rd December 2015, 12:31
  3. Seeking advise on the QtScript replacement
    By TorAn in forum Qt Programming
    Replies: 3
    Last Post: 5th November 2015, 17:18
  4. Seeking Suggestions for Multi-Threaded Application Design
    By swamyonline in forum Qt Programming
    Replies: 7
    Last Post: 1st May 2014, 17:19
  5. advise sought on TreeView model design
    By QPlace in forum Qt Programming
    Replies: 0
    Last Post: 25th June 2009, 15:36

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.