Opened 14 years ago

Closed 11 years ago

Last modified 10 years ago

#2796 closed Bugs (fixed)

interprocess::file_lock has incorrect behavior when win32 api is enabled

Reported by: Kelly K. Heller <kkheller@…> Owned by: Ion Gaztañaga
Milestone: Component: interprocess
Version: Boost 1.38.0 Severity: Problem
Keywords: file descriptor fd getfd file handle handle file pointer win32 winapi fstream ifstream ofstream std createfile lock locking Cc:

Description

(Above all else, I must say.... boost is awesome. I am raving fan of boost. Many, many thanks to all the talented boost developers.)

BUG DESCRIPTION:

Either the IPC file_lock documentation needs fixing, or else there is a bug in the way file_lock uses win32 file handles and LockFileEx.

This part of the boost documentation is incorrect when the win32 api is enabled:

http://www.boost.org/doc/libs/1_36_0/doc/html/interprocess/synchronization_mechanisms.html#interprocess.synchronization_mechanisms.file_lock.file_lock_careful_iostream

The problem with the sample code at the above URL is that on windows, "fstream file" and "file_lock f_lock" both will hold TWO DIFFERENT file handles. Of course both of those objects wrap the same exact file on disk, but it is _crucial_ (and in this case deadly) to realize that they wrap different HANDLES.

So... when using the win32 api in boost file_lock, the last line of code in the sample from the URL will always fail.

This will always fail:

file.flush();

Windows will produce an ERROR_LOCK_VIOLATION. As I explain below, the reason why this happens is that locking in the windows api actually locks write-access to the file based on the HANDLE, not based on the process (pid) that obtained the locking rights.

This basically makes boost file_lock incompatible, or not successfully ported, to windows. I essentially "lock myself out of the file" when I use the file_lock. Obviously that is _not_ what one wants. We want to lock other processes out of the file, but not lock ourselves out.

Please note the following win32 documentation:

http://msdn.microsoft.com/en-us/library/aa365203(VS.85).aspx

The interesting part about LockFileEx is the following:

"Remarks .....

If the locking process opens the file a second time, it cannot access the specified region through this second handle until it unlocks the region..... "

The important thing about that is that LockFileEx is doing MORE than making sure foreign processes are locked out of my file. LockFileEx will also keep my process (the process obtaining the lock) from writing to the file, unless I am careful to use an IDENTICAL file handle.

As far as I can see, this makes LockFileEx very different from flock().

So, if I am to follow the windows advice for using LockFileEx, then I believe what I need to do is make sure that the same file handle I use to write to my file is IDENTICAL to the file handle used by my boost file_lock object.

Unfortunately, I cannot see any way to do this. And unless I can find a way, then it seems like boost::interprocess:file_lock is not useful at all when the win32 api is enabled.

in the ctor of the file_lock, "open_existing_file" is called, which calls the winapi function CreateFileA.

CreateFileA gives you a new file handle. This file handle is stored (privately) in:

file_lock::m_file_hnd

When you then proceed to _lock_ the file_lock, the winapi function LockFileEx.

LockFileEx takes a handle as an argument. As we would expect, the handle that gets passed in is the same handle as file_lock::m_file_hnd.

The problem is that the win32 api will now lock out (prevent) all writes to the file that are not writing via that same file handle.

That means that even the process that obtained and now holds the locked file_lock is prevented from writing to the file.

This is the windows error that happens:

33 The process cannot access the file because another process has locked a portion of the file. ERROR_LOCK_VIOLATION

Because "file_lock::m_file_hnd" is a private member, I cannot see any way for me to use any object (and file object, whether it be a win32 object that I construct, or a std::fstream, or some other file object)... I cannot see a way for myself to get a file object with the SAME handle as file_lock::m_file_hnd, which is what I must do if I even am going to actually write to the file that i have locked with file_lock.

Change History (7)

comment:1 by Kelly K. Heller <kkheller@…>, 14 years ago

Version: Boost 1.37.0Boost 1.38.0

comment:2 by Ion Gaztañaga, 12 years ago

Resolution: fixed
Status: newclosed

Changed documentation in Boost 1.47

comment:3 by Kelly Heller <kkheller@…>, 11 years ago

I would be very interested to know the text that has been changed or added in the new documentation. I compared the 1.36 documentation to the current 1.47 documentation today, and I cannot find any updates related to this bug case. Thank you for your help.

comment:4 by Dominik Wild <d.wild@…>, 11 years ago

Milestone: Boost 1.39.0
Resolution: fixed
Status: closedreopened

The bug description is accurate. Neither the code nor the documentation were fixed in 1.47.

Others have experienced this bug as well: http://stackoverflow.com/questions/5425064/scoped-lock-doesnt-work-on-file

comment:5 by Ion Gaztañaga, 11 years ago

Resolution: fixed
Status: reopenedclosed

It was actually fixed in Boost.1.48, as the change was not merged to release branch for Boost 1.47. In the example, the name of the lock file was changed and a note warning about windows behaviour is added. If we want to use native file locking functions from winows we can't much more.

comment:6 by sumeet@…, 10 years ago

I found the same issue the hard way. I must say the documentation is still misleading, otherwise I wouldn't have gone down this path. I'm going to try named mutexes now...

in reply to:  6 comment:7 by anonymous, 10 years ago

Boost rocks though. Thanks for all your efforts. Replying to sumeet@…:

I found the same issue the hard way. I must say the documentation is still misleading, otherwise I wouldn't have gone down this path. I'm going to try named mutexes now...

Note: See TracTickets for help on using tickets.