C ++ / Win32:如何等待挂起的删除完成 [英] C++/Win32: How to wait for a pending delete to complete

查看:80
本文介绍了C ++ / Win32:如何等待挂起的删除完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

已解决:

  • Workable solution: sbi's answer
  • Explanation for what really happens: Hans's answer
  • Explanation for why OpenFile doesn't pass through "DELETE PENDING": Benjamin's answer

问题:

我们的软件在很大程度上是专有脚本语言的解释器引擎。该脚本语言具有创建文件,处理文件然后删除文件的能力。这些都是单独的操作,在这些操作之间没有打开文件句柄。

Our software is in large part an interpreter engine for a proprietary scripting language. That scripting language has the ability to create a file, process it, and then delete the file. These are all separate operations, and no file handles are kept open in between these operations.

(即在文件创建过程中,先创建一个句柄,然后将其用于写入,然后在文件处理部分,一个单独的文件句柄打开文件,从中读取文件,并在EOF关闭。最终,delete使用:: DeleteFile,该文件仅使用文件名,而不使用

(I.e. during the file creation, a handle is created, used for writing, then closed. During the file processing portion, a separate file handle opens the file, reads from it, and is closed at EOF. And finally, delete uses ::DeleteFile which only has use of a filename, not a file handle at all).

最近,我们开始意识到某个特定的宏(脚本)有时无法在随后的某个随机时间创建文件(即,它在创建,处理,删除的前一百次迭代中成功,但是当它又回到一百次创建时,Windows答复访问被拒绝。)

Recently we've come to realize that a particular macro (script) fails sometimes to be able to create the file at some random subsequent time (i.e. it succeeds during the first hundred iterations of "create, process, delete", but when it comes back to creating it a hundred and first time, Windows replies "Access Denied").

更深入地研究这个问题,我编写了一个非常简单的程序来遍历以下内容:

Looking deeper into the issue, I have written a very simple program that loops over something like this:

while (true) {
    HANDLE hFile = CreateFileA(pszFilename, FILE_ALL_ACCESS, FILE_SHARE_READ,
                               NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
        return OpenFailed;

    const DWORD dwWrite = strlen(pszFilename);
    DWORD dwWritten;

    if (!WriteFile(hFile, pszFilename, dwWrite, &dwWritten, NULL) || dwWritten != dwWrite)
        return WriteFailed;

    if (!CloseHandle(hFile))
        return CloseFailed;

    if (!DeleteFileA(pszFilename))
        return DeleteFailed;
}

如您所见,这直接指向Win32 API,实在是太糟糕了简单。我创建了一个文件,写入该文件,关闭该句柄,将其删除,冲洗,然后重复...

As you can see, this is direct to the Win32 API and is pretty darn simple. I create a file, write to it, close the handle, delete it, rinse, repeat...

但是在某个地方,我会被拒绝访问(5)在CreateFile()调用期间出错。查看sysinternal的ProcessMonitor,可以发现潜在的问题是在尝试再次创建文件时文件上有待删除的文件。

But somewhere along the line, I'll get an Access Denied (5) error during the CreateFile() call. Looking at sysinternal's ProcessMonitor, I can see that the underlying issue is that there is a pending delete on the file while I'm trying to create it again.

问题:


  • 是否可以等待删除完成?

  • 是否可以检测到文件正在等待删除?

我们尝试了第一种选择,方法是简单地使用WaitForSingleObject() HFILE。但是HFILE始终在执行WaitForSingleObject之前关闭,因此WaitForSingleObject始终返回WAIT_FAILED。显然,尝试等待关闭的句柄不起作用。

We have tried the first option, by simply WaitForSingleObject() on the HFILE. But the HFILE is always closed before the WaitForSingleObject executes, and so WaitForSingleObject always returns WAIT_FAILED. Clearly, trying to wait for the closed handle doesn't work.

我可以等待文件所在文件夹的更改通知。但是,看起来非常费时的开销,只会偶尔遇到问题(例如:在我的Windows 7 x64 E6600 PC上进行的测试中,它通常在12000+迭代上失败-在其他计算机上,它可能会在7迭代或15或56或从不)。

I could wait on a change notification for the folder that the file exists in. However, that seems like an extremely overhead-intensive kludge to what is a problem only occasionally (to wit: in my tests on my Windows 7 x64 E6600 PC it typically fails on iteration 12000+ -- on other machines, it can happen as soon as iteration 7 or 15 or 56 or never).

我无法辨别明确允许使用该以太坊的任何CreateFile()参数。不管CreateFile有什么参数,在文件等待删除时打开文件进行任何访问都是不可行的。

I have been unable to discern any CreateFile() arguments that would explicitly allow for this ether. No matter what arguments CreateFile has, it really is not okay with opening a file for any access when the file is pending deletion.

我可以在Windows XP框和x64 Windows 7框上看到此行为,我可以肯定这是Microsoft按预期的核心NTFS行为。因此,我需要一个解决方案,允许操作系统在尝试继续操作之前完成删除操作,最好不要不必要地占用CPU周期,也没有监视此文件所在的文件夹的最大开销(如果可能)。

And since I can see this behavior on both an Windows XP box and on an x64 Windows 7 box, I am quite certain that this is core NTFS behavior "as intended" by Microsoft. So I need a solution that allows the OS to complete the delete before I attempt to proceed, preferably without tying up CPU cycles needlessly, and without the extreme overhead of watching the folder that this file is in (if possible).

1 是的,此循环在写入失败或关闭失败(泄漏)时返回,但是由于这是一个简单的控制台测试应用程序,因此该应用程序本身退出,并且Windows保证所有句柄进程完成后,由操作系统关闭。因此,这里没有泄漏。

1 Yes, this loop returns on a failure to write or a failure to close which leaks, but since this is a simple console test application, the application itself exits, and Windows guarantees that all handles are closed by the OS when a process completes. So no leaks exist here.

bool DeleteFileNowA(const char * pszFilename)
{
    // Determine the path in which to store the temp filename
    char szPath[MAX_PATH];
    strcpy(szPath, pszFilename);
    PathRemoveFileSpecA(szPath);

    // Generate a guaranteed to be unique temporary filename to house the pending delete
    char szTempName[MAX_PATH];
    if (!GetTempFileNameA(szPath, ".xX", 0, szTempName))
        return false;

    // Move the real file to the dummy filename
    if (!MoveFileExA(pszFilename, szTempName, MOVEFILE_REPLACE_EXISTING))
        return false;

    // Queue the deletion (the OS will delete it when all handles (ours or other processes) close)
    if (!DeleteFileA(szTempName))
        return false;

    return true;
}


推荐答案

首先将文件重命名为删除,然后将其删除。

First rename the file to be deleted, and then delete it.

使用 GetTempFileName()获得唯一的名称,然后使用 MoveFile()重命名文件。然后删除重命名的文件。如果实际删除确实是异步的,并且可能与创建相同文件(如您的测试似乎表明的那样)冲突,那么应该可以解决该问题。

Use GetTempFileName() to obtain a unique name, and then use MoveFile() to rename the file. Then delete the renamed file. If the actual deletion is indeed asynchronous and might conflict with the creation of the same file (as your tests seems to indicate), this should solve the problem.

当然,如果您的分析正确,并且文件操作在某种程度上是异步的,则可能会导致您在重命名完成之前尝试删除文件的问题。但是,您始终可以尝试在后台线程中进行删除。

Of course, if your analysis is right and file operations happen somewhat asynchronous, this might introduce the problem that you attempt to delete the file before the renaming is done. But then you could always keep trying to delete in a background thread.

如果汉斯是对的(并且我倾向于相信他的分析),那么搬家可能就不会帮助,因为您实际上可能无法重命名由另一个进程打开的文件。 (但是,您可能会知道,我不知道。)如果确实如此,我想出的唯一其他方法是继续尝试。您将需要等待几毫秒,然后重试。如果没有帮助,请保持超时以放弃。

If Hans is right (and I'm inclined to believe his analysis), then moving might not really help, because you might not be able to actually rename a file that's open by another process. (But then you might, I don't know this.) If that's indeed the case, the only other way I can come up with is "keep trying". You would have to wait for a few milliseconds and retry. Keep a timeout to give up when this doesn't help.

这篇关于C ++ / Win32:如何等待挂起的删除完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆