【问题标题】:File Unlocking and Deleting as single operation文件解锁和删除作为单一操作
【发布时间】:2009-12-19 14:05:52
【问题描述】:

请注意,这不是 File r/w locking and unlink 的重复。 (区别——平台。文件的锁定和删除等操作的语义完全不同,因此结果会有所不同。

我有以下问题。我想创建一个基于文件系统的会话存储,其中每个会话数据都存储在以会话 ID 命名的简单文件中。

我想要以下 API:write(sid,data,timeout)read(sid,data,timeout)remove(sid) 其中 sid== 文件名,另外我想要某种可以删除所有超时会话的 GC。

如果您使用单个进程,这是非常简单的任务,但在使用多个进程甚至共享文件夹时绝对不是微不足道的。

我想到的最简单的解决方案是:

write/read:
   hanlde=CreateFile
   LockFile(handle)
   read/write data
   UnlockFile(handle)
   CloseHanlde(handle)

GC (for each file in directory)
   hanlde=CreateFile
   LockFile(handle)
   check if timeout occured
     DeleteFile
   UnlockFile(handle)
   CloseHanlde(handle)

但是 AFIAK 我不能在打开的锁定文件上调用 DeleteFile(不像在 Unix 中文件锁定是 不是强制性的,打开的文件允许取消链接。

但是如果我将DeleteFile 放在锁定循环之外,可能会发生不良情况

GC - CreateFile/LockFile/Unlock/CloseHandle,
write - oCreateFile/LockFile/WriteUpdatedData/Unlock/CloseHandle
GC - DeleteFile

有人知道如何解决此类问题吗?有没有什么技巧可以让 结合文件锁定和文件删除或对文件原子进行操作(Win32)?

注意事项:

  • 我不想使用数据库,
  • 我正在寻找适用于 NT 5.01 及更高版本的 Win32 API 的解决方案

谢谢。

【问题讨论】:

  • 对我来说当然是个骗子。请解释差异,否则很可能会被关闭。
  • 添加解释——POSIX 和 Win32 需要完全不同的解决方案

标签: winapi file-locking


【解决方案1】:

我真的不明白这应该如何工作。但是,可以删除由另一个进程打开的文件。创建文件的进程必须为 CreateFile() 的 dwShareMode 参数使用 FILE_SHARE_DELETE 标志。随后的 DeleteFile() 调用将成功。在关闭文件的最后一个句柄之前,该文件实际上不会从文件系统中删除。

【讨论】:

  • 好的,我明白了,看起来我根本不需要 LockFile。如果我指定CreateFile("file.txt",...,FILE_SHARE_DELETE,...) 而不指定FILE_SHARE_READ | FILE_SHARE_WRITE,则只有一个线程/进程能够保持文件打开。我对吗?所以我根本不需要锁定,对吗?
  • 其实 Windows 看起来和 Unix 太不一样了:Win32 : CreateFile(ok), DeleteFile(ok), CreateFile(fail)。 Unix: open(ok), unlink(ok), open(ok -- 另一个文件)。这让我感到困惑。
【解决方案2】:

您当前的记录中有数据允许 GC 确定记录是否超时。如何使用“TooLateWeAlreadyTimedItOut”标志扩展该家务信息。

 GC sets TooLateWeAlreadyTimedItOut = true
 Release lock
    <== writer comes in here, sees the "TooLate" flag and so does not write
 GC deletes

换句话说,我们正在使用一种乐观锁定方法。这确实需要在 Writer 中增加一些额外的复杂性,但现在您不再依赖于任何特定于操作系统的皱纹。

我不清楚这个案子会发生什么:

 GC checks timeout
 GC deletes
 Writer attempts write, and finds no file ...

你为这个案例计划的任何东西也可以用在“TooLate”案例中

编辑添加:

你说过这个序列发生是有效的:

 GC Deletes
 (Very slightly later) Writer attempts a write, sees no file, creates a new one

作者可以将“tooLate”标志视为与这种情况相同。它只是创建一个 new 文件,具有不同的名称,使用版本号作为其名称的尾随部分。第一次打开会话文件需要目录搜索,但随后您可以将最新的名称存储在会话中。

这确实假设给定会话只能有一个 Writer 线程,或者我们可以在创建文件的两个 Writer 线程之间进行调解,但这必须为您的简单 GC/Writer 案例工作。

【讨论】:

  • 我希望作者“禁用”TooLate 的问题——意味着更新文件。所以你提出的解决方案对我无效。第二点(作者尝试写入然后它应该创建文件)
  • 你不需要禁用太晚,你可以重新排序操作。我会编辑解释。
【解决方案3】:

对于 Windows,您可以在 CreateFile 中使用 FILE_FLAG_DELETE_ON_CLOSE 选项 - 这将导致文件在您关闭句柄时被删除。但我不确定这是否满足您的语义(因为我不相信您可以清除 delete-on-close 属性。

这是另一个想法。在删除文件之前重命名文件怎么样?在您决定删除文件后,您根本无法关闭写入的窗口,但是如果您在删除文件之前重命名文件怎么办?然后当写入进来时,它会看到会话文件不存在并重新创建它。

要记住的关键是您根本无法关闭有问题的窗口。恕我直言,有两种解决方案:

  1. 添加像提到的 djna 这样的标志或
  2. 要求获取一个名为 mutex 的每个会话,它具有在会话上序列化写入的不幸副作用。

拥有 TooLate 标志的缺点是什么?换句话说,如果您过早地删除文件会出现什么问题?毕竟你的系统必须处理不存在的文件......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-27
    • 2013-10-08
    • 2022-10-19
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    • 2015-06-30
    相关资源
    最近更新 更多