文件解锁和删除为单个操作

时间:2009-12-19 14:05:52

标签: winapi file-locking

请注意,这与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的解决方案

感谢。

3 个答案:

答案 0 :(得分:2)

我真的不明白这是怎么回事。但是,可以删除由另一个进程打开的文件。创建文件的过程必须使用FILE_SHARE_DELETE标志来创建CreateFile()的dwShareMode参数。随后的DeleteFile()调用将成功。该文件实际上不会从文件系统中删除,直到它的最后一个句柄关闭。

答案 1 :(得分:1)

您当前在记录中有数据,允许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案例来说,这必须是正确的。

答案 2 :(得分:0)

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

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

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

  1. 添加像djna提到的标志或
  2. 要求获取一个名为mutex的会话,这会导致在会话中序列化写入的不幸副作用。
  3. 拥有TooLate标志的缺点是什么?换句话说,如果过早删除文件会出现什么问题?毕竟你的系统必须处理文件不存在......