PDA

View Full Version : QFilesystemwatcher in another thread



RenanBS
3rd May 2013, 22:45
Hello,

I'm trying to monitor a file deletion from a certain path.
While this file is not deleted, my application shouldn't do anything.
Of course, if something goes wrong and the file is not deleted, there will be a timeout.

I have a 3 signals depending on what happens with the file, removed, modified or created. When the file is removed, for example, the signal removed set a variable "finished" to break the loop on the file main.cpp, but it looks like it isn't. Any help on this?

My test code is attached here: 9010

If this is needed, my OS is Windows 7 Professional.

Thanks,
Renan

anda_skoa
4th May 2013, 10:07
Your problem is that you are doing a cross-thread signal/slot connection but do not run an event loop in the receiver object's thread (main thread).

So when the object in the worker thread emits its signals, the event that would call the MainClass' slots cannot be delivered.

However, the main question is why do you need a thread at all?

Cheers,
Kevin

RenanBS
6th May 2013, 12:03
I need to know when a particular file has been deleted in order to proceed with my application.
I need to block the main thread of my application waiting for it to be deleted. There is no need at all to have another thread...
Do you have any suggestions on how to do it?

Thanks,
Renan

wysota
6th May 2013, 13:45
You don't need to block your main thread while the file is not deleted. You need to do something when the file is deleted. You don't need any extra threads for that.

RenanBS
6th May 2013, 14:27
We have a application here were I work, that when we write a file ("close.txt") in some specific path it closes itself. But this operation takes some time. It depends on what it was doing... Sometimes it takes more than 200 seconds to do it.
My application will write this file to close our other application and will wait until it closes. My signal is when the file is deleted.
The problem is that I need to wait for it to be deleted. I thought of blocking the main thread, but like you said, I don't need to do it. So how should I proceed with this?

Renan

wysota
6th May 2013, 14:42
You just return to the event loop and let the filesystem watcher call your slot you connected to one of its signals. Since your example doesn't run an event loop at all, you need to adjust it for the loop to be running.

RenanBS
6th May 2013, 15:14
I did it using the class QEventLoop. Would it be the recommended way to run this event loop?
This is what I did:

main.cpp:


#include <QCoreApplication>
#include <QThread>

#include <iostream>

#include "filewatcher.h"

int main (int argc, char *argv[])
{
QCoreApplication a (argc, argv);
QEventLoop loop;
FileWatcher *close = new FileWatcher ("c:/home/rs94036/");

QObject::connect (close, SIGNAL (removed ()), close, SLOT (removedSlot ()));
QObject::connect (close, SIGNAL (modified ()), close, SLOT (modifiedSlot ()));
QObject::connect (close, SIGNAL (created ()), close, SLOT (createdSlot ()));
QObject::connect (close, SIGNAL (exitLoop ()), &loop, SLOT (quit ()));
close->closeSepApp ();

loop.exec ();

std::cout << "AFTER LOOP" << std::endl;

return 0;
}


FileWatcher.cpp:


#include <QFileInfo>
#include <QTextStream>

#include "FileWatcher.h"

#include <iostream>

FileWatcher::FileWatcher (const QString &path)
{
monitoringPath = path;
status = FILE_TIMEOUT;
}

bool FileWatcher::closeSepApp ()
{
monitoringFileName = "close.txt";
QFile *close = new QFile (monitoringPath + monitoringFileName);
if (!close->exists ())
{
if (close->open (QIODevice::WriteOnly))
{
// Write something on it
QTextStream *text = new QTextStream (close);
*text << "1";
close->close ();
}
else
return false;
}
else
return false;

startMonitoring ();
return true;
}

void FileWatcher::startMonitoring ()
{
existsBeforeEvent = QFileInfo (monitoringPath + monitoringFileName).exists();
status = existsBeforeEvent ? FILE_CHANGED : FILE_TIMEOUT;

mon = new QFileSystemWatcher ();
connect (mon, SIGNAL (fileChanged (QString)), this, SLOT (onFileChanged (QString)));
mon->addPath (monitoringPath + monitoringFileName);
}

void FileWatcher::onFileChanged (const QString& path)
{
bool existsAfterEvent = QFileInfo (path).exists();

if (existsBeforeEvent && !existsAfterEvent)
emit removed ();
else if (!existsBeforeEvent && existsAfterEvent)
emit created ();
else
emit modified ();
}

void FileWatcher::removedSlot ()
{
std::cout << "FILE_REMOVED" << std::endl;
emit exitLoop ();
}

void FileWatcher::modifiedSlot ()
{
std::cout << "FILE_CHANGED" << std::endl;
emit exitLoop ();
}

void FileWatcher::createdSlot ()
{
std::cout << "FILE_CREATED" << std::endl;
emit exitLoop ();
}


FileWatcher.h:


#ifndef FileWatcher_H
#define FileWatcher_H

#include <QFileSystemWatcher>
#include <QObject>
#include <QEventLoop>

enum FileStatus
{
FILE_CREATED,
FILE_CHANGED,
FILE_REMOVED,
FILE_TIMEOUT
};

class FileWatcher : public QObject
{
Q_OBJECT
public:
FileWatcher (const QString& path);
bool closeSepApp ();

private:
QString monitoringPath;
QString monitoringFileName;
bool existsBeforeEvent;
FileStatus status;
QFileSystemWatcher *mon;

public slots:
void startMonitoring ();

protected slots:
void onFileChanged (const QString& path);

signals:
void removed ();
void modified ();
void created ();
void exitLoop ();

public slots:
void removedSlot ();
void modifiedSlot ();
void createdSlot ();

};

#endif // FileWatcher_H


Renan

RenanBS
7th May 2013, 12:45
Since this method is working fine, I'm assuming it is correct.

Thanks.

wysota
7th May 2013, 13:44
You might have just called a.exec() instead.

RenanBS
7th May 2013, 14:09
I thought about that.
In the example I could have done this. But in my application I don't have access to the QCoreApplication a anymore...

Thanks.

wysota
7th May 2013, 20:05
Sure you did -- QCoreApplication::instance() is a static method that returns a pointer to the application object.