Delphi 10.3 Linux 独占文件访问
Delphi 10.3 Linux exclusive file access
如何使用文件流锁定 Linux 中的文件?
像下面的示例一样创建文件流在 Windows 中完美运行,文件被锁定并且在流被释放之前无法在其他会话中删除或写入。在 Linux 下,我可以毫无问题地删除文件或在其他会话中写入文件。
var f: TFileStream;
...
f := TFileStream.Create(TPath.Combine(FTemp, lowerCase(Name)), fmOpenReadWrite + fmCreate);
...
2020 年 1 月 1 日的新发现
Linux 不会像 Windows 那样自动对文件应用原子锁。所以我尝试在创建文件后应用锁:
function flock(handle, operation: integer): integer; cdecl; external libc name _PU + 'flock';
const
LOCK_EX = 2;
...
f := TFileStream.Create(fn, fmCreate, fmShareExclusive);
flock(f.handle, LOCK_EX);
存在一个小的竞争条件,因为创建文件和锁定它不是一个步骤,但对于我的应用程序来说这不是问题。在 linux 控制台上查看创建的锁定文件时,差异很明显:
没有 flock():
mint@minti:/tmp/itclock$ lsof wirsing
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
_TestLibB 5417 mint 14u REG 8,1 8 2755101 wirsing
使用 flock():
mint@minti:/tmp/itclock$ lsof wirsing
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
_TestLibB 6365 mint 14uW REG 8,1 0 2755117 wirsing
区别是大W表示独占锁。
不幸的是,这并不能解决问题,因为创建第二个文件流只会在同一进程中创建第二个独占锁,并且仍然可以从其他进程中删除文件。如果有办法从 delphi 中读取 lsof <file>
的扩展属性 ...
又一发现(新年新思路)
因为我 运行 我的测试作为单元测试并在同一进程中创建多个对象来测试锁,这可能是原因,因为 Windows 甚至不允许从内部访问锁定的文件同样的过程。这在 Linux 中似乎有所不同。我需要一些行为类似于 Windows 的东西——如果它被锁定在不同的进程或同一进程的线程中应该没有区别。也许 Linux 提供了一种完全不同的方式来实现这种锁定机制?
还有:非常感谢任何帮助!
最后我找到了一个至少满足我的要求的可用解决方案:
在 Windows 中,我继续使用 fmShareExclusive 的简单方法。在 Linux 中,我应用了上面问题中描述的 FileLock。为了检查独占锁,我通过 popen 运行 命令行并在删除锁文件之前捕获结果,然后 creating/locking 它。
lsof -Fl <my flock file name>
如果存在锁,则输出三行:
p7590
f14
lW
我在结果中寻找 lW
,表明文件上有独占锁,我可以根据需要对此做出反应。
如果进程崩溃,此解决方案仍然有效,因为文件锁也会消失。
我知道这不是一个非常优雅的解决方案,但它似乎足够鲁棒和可靠。
非常欢迎提出意见和建议!
如何使用文件流锁定 Linux 中的文件?
像下面的示例一样创建文件流在 Windows 中完美运行,文件被锁定并且在流被释放之前无法在其他会话中删除或写入。在 Linux 下,我可以毫无问题地删除文件或在其他会话中写入文件。
var f: TFileStream;
...
f := TFileStream.Create(TPath.Combine(FTemp, lowerCase(Name)), fmOpenReadWrite + fmCreate);
...
2020 年 1 月 1 日的新发现
Linux 不会像 Windows 那样自动对文件应用原子锁。所以我尝试在创建文件后应用锁:
function flock(handle, operation: integer): integer; cdecl; external libc name _PU + 'flock';
const
LOCK_EX = 2;
...
f := TFileStream.Create(fn, fmCreate, fmShareExclusive);
flock(f.handle, LOCK_EX);
存在一个小的竞争条件,因为创建文件和锁定它不是一个步骤,但对于我的应用程序来说这不是问题。在 linux 控制台上查看创建的锁定文件时,差异很明显:
没有 flock():
mint@minti:/tmp/itclock$ lsof wirsing
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
_TestLibB 5417 mint 14u REG 8,1 8 2755101 wirsing
使用 flock():
mint@minti:/tmp/itclock$ lsof wirsing
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
_TestLibB 6365 mint 14uW REG 8,1 0 2755117 wirsing
区别是大W表示独占锁。
不幸的是,这并不能解决问题,因为创建第二个文件流只会在同一进程中创建第二个独占锁,并且仍然可以从其他进程中删除文件。如果有办法从 delphi 中读取 lsof <file>
的扩展属性 ...
又一发现(新年新思路)
因为我 运行 我的测试作为单元测试并在同一进程中创建多个对象来测试锁,这可能是原因,因为 Windows 甚至不允许从内部访问锁定的文件同样的过程。这在 Linux 中似乎有所不同。我需要一些行为类似于 Windows 的东西——如果它被锁定在不同的进程或同一进程的线程中应该没有区别。也许 Linux 提供了一种完全不同的方式来实现这种锁定机制?
还有:非常感谢任何帮助!
最后我找到了一个至少满足我的要求的可用解决方案:
在 Windows 中,我继续使用 fmShareExclusive 的简单方法。在 Linux 中,我应用了上面问题中描述的 FileLock。为了检查独占锁,我通过 popen 运行 命令行并在删除锁文件之前捕获结果,然后 creating/locking 它。
lsof -Fl <my flock file name>
如果存在锁,则输出三行:
p7590
f14
lW
我在结果中寻找 lW
,表明文件上有独占锁,我可以根据需要对此做出反应。
如果进程崩溃,此解决方案仍然有效,因为文件锁也会消失。
我知道这不是一个非常优雅的解决方案,但它似乎足够鲁棒和可靠。
非常欢迎提出意见和建议!