How do I monitor the file lock to see when it is released? [C ++]

I am looking for a way to create a program in unmanaged C ++ that waits until the file is unlocked (as it is no longer used in it), but something. I had no luck finding how to do this, any help would be appreciated!

UPDATE: I may have answered my own question, take a look below and tell you what you think.

UPDATE: all that really matters is the file is writable, it doesn't matter if it's still in use.

0


a source to share


5 answers


Here is one possible solution to my problem: does anyone see a problem with this?

#include <iostream>
#include <fstream>
#include <windows.h>
using namespace std;
void main(int argc, char ** argv) {
    if (argc < 2 || argc > 2) {
        return;
    }

    ofstream myfile;
    myfile.open(argv[1], ios_base::app);
    while (!myfile.is_open()) { Sleep(100); myfile.open(argv[1], ios_base::app); }
    myfile.close();

    // file should now be unlocked..
}

      



Thanks again!

UPDATE: changed the code to be more complete.

0


a source


Something like this will wait without wasting CPU cycles.

HANDLE h = FindFirstChangeNotification("C:\Path to folder holding file", FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);

while(true)
{
    if (CheckLockFile("C:\Path to file"))
    {
        // Do something
        break;
    }

    WaitForSingleObject(h, APPROPRIATE_TIMEOUT_VALUE);
    FindNextChangeNotification(h);
}

bool CheckLockFile(char* FilePath)
{
    HANDLE fh = CreateFile(FilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0,NULL);
    if (fh == INVALID_HANDLE_VALUE)
    {
        return false; 
    }
    CloseHandle(fh);

    return true;
}

      



This assumes that the file-locked application has it open for writing.

+2


a source


Create a loop that calls :: CreateFile () every 5 seconds until it succeeds. Pass 0 in the dwShareMode argument to make sure there is no other process that has the file open.

+1


a source


It looks like you want to access the file after another program has released the lock. UNIX (and Cygwin) gives you this behavior by simply locking the file.

By using something like ScopeGuard

you can make it File_locker

unnecessary, but if you are not using ScopeGuard

, follow these steps:

UNIX:

#include <stdexcept>
#include <string>
#include "sys/file.h" //flock
#include "sys/fcntl.h" //open

class File_locker {
    int file_descriptor;
  public:
    File_locker(std::string filename)
    {
        // you can use errno to determine why the open/flock failed,
        // but this is a demo, not production code

        file_descriptor = ::open(filename.c_str(), O_RDWR);
        if (file_descriptor < 0)
            throw std::runtime_error((std::string("unable to open file ")
                + filename).c_str());
        if (::flock(file_descriptor, LOCK_EX)) {
            ::close(file_descriptor);
            throw std::runtime_error((std::string("unable to flock file ")
                + filename).c_str());
        }
    }
    ~File_locker()
    {
        ::flock(file_descriptor, LOCK_UN); // don't forget to unlock
        ::close(file_descriptor);
    }
};

      

On Windows, it seems like you should poll the file.

Window:

#include <string>
#include "windows.h"

class File_locker {
    HANDLE file_handle;
    static const int MAX_TRIES = 10;
    static const int SLEEP_INTERVAL = 500;

  public:
    File_locker(std::string filename)
    {
        // you can use GetLastError() to determine why the open failed,
        // but this is a demo, not production code
        for (int i = 0; i < MAX_TRIES; ++i) {
            file_handle = ::CreateFile(filename.c_str(),
                                       GENERIC_READ | GENERIC_WRITE,
                                       0,
                                       NULL,
                                       OPEN_EXISTING,
                                       FILE_ATTRIBUTE_NORMAL,
                                       NULL);
            if (file_handle != INVALID_HANDLE_VALUE)
                return;
            ::Sleep(SLEEP_INTERVAL);
            }
            throw std::runtime_error((std::string("unable to open file ")
                + filename).c_str());
    }
    ~File_locker()
    {
        ::CloseHandle(file_handle);
    }
};

      

Use it like this:

#include <fstream>
#include <stdexcept>

// .. define File_locker, as above

int main()
{
    try {
        File_locker fl("filename.txt");
        // once fl is constructed, nobody else has the file locked
        std::fstream file("filename.txt");
        // ...
        return 0;
    }
    catch (std::runtime_error& ex)
    {
        // just bail
        return 1;
    }
}

      

0


a source


Just use system file notification locks

-1


a source







All Articles