what is the Windows equivalent of unix's flock(h, LOCK_SH)?

1.6k Views Asked by At

how do you get a read-lock on Windows? like on Linux you'd do

#include <fcntl.h>
#include <sys/file.h>
int main(int argc, char **argv){
    int h=open(argv[0],O_RDONLY);
    flock(h,LOCK_SH);
    flock(h,LOCK_UN);
    close(h);
}

what's the Windows equivalent?

2

There are 2 best solutions below

0
Anders On

LockFileEx for basic locking. For a very soft lock there are also opportunistic locks.

4
hanshenrik On

expanding on @Anders's answer, the answer is LockFileEx, and the type of lock is decided by the dwFlags arguments,

linux=>windows

LOCK_SH => 0

LOCK_EX => LOCKFILE_EXCLUSIVE_LOCK

LOCK_NB => LOCKFILE_FAIL_IMMEDIATELY

the Windows API is quite a bit more complex (and powerful) than the Linux one, allowing you to lock "just parts" of the file, but you're free to effectively lock the whole file by just specifying that you want "the first 18446744073709551615 bytes locked" (meaning you want the first 18.45 exabytes of the file locked...), you're also able to "lock bytes that doesn't exist yet", hence a rough port of the code in the top post would be:

#include <cstdint>
#include <iostream>
#include <windows.h>
int main(int argc, char **argv){
    HANDLE handle = CreateFileA(argv[0], GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (handle == INVALID_HANDLE_VALUE) {
        throw std::runtime_error("CreateFile failed with error " + std::to_string(GetLastError()) + " for " + std::string(argv[0]));
    }
    const DWORD allBitsSet = ~DWORD(0);
    DWORD flags = 0; // LOCK_SH = 0, LOCK_EX = LOCKFILE_EXCLUSIVE_LOCK, LOCK_NB = LOCKFILE_FAIL_IMMEDIATELY
    _OVERLAPPED overlapped1 = {0};
    _OVERLAPPED overlapped2 = {0};
    if (!LockFileEx(handle, flags, 0, allBitsSet, allBitsSet, &overlapped1)) {
        throw std::runtime_error("LockFileEx failed with error " + std::to_string(GetLastError()));
    }
    if(!UnlockFileEx(handle, 0, allBitsSet, allBitsSet, &overlapped2)) {
        throw std::runtime_error("UnlockFileEx failed with error " + std::to_string(GetLastError()));
    }
    CloseHandle(handle);
}