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

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

问题描述

已解决:

*可行解决方案:@sbi

*说明发生了什么:@Hans

* Explanation为什么OpenFile不通过DELETE PENDING:@Benjamin



问题:

我们的软件在很大程度上是用于专有脚本语言的解释器引擎。该脚本语言具有创建文件,处理文件,然后删除文件的能力。这些都是单独的操作,并且在这些操作之间不保持打开文件句柄。 (即在文件创建期间创建句柄,用于写入,然后关闭。在文件处理部分,一个单独的文件句柄打开文件,从中读取,并在EOF处关闭。最后,delete使用:: DeleteFile只有使用文件名,而不是文件句柄)。



最近我们意识到一个特定的宏(脚本)有时失败在一些随机的时间(即它在创建,处理,删除的前100次迭代中创建文件),但是当它回到创建它一百次,Windows回复访问被拒绝。) / p>

深入探讨这个问题,我写了一个非常简单的程序,循环这样的东西:

  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,简单。我创建一个文件,写入它,关闭句柄,删除它,冲洗,重复...



但沿着这一行, (5)在CreateFile()调用期间的错误。查看sysinternal的ProcessMonitor,我可以看到底层的问题是,当我尝试再次创建它时,文件有一个挂起的删除。



问题:

*是否有办法等待删除完成?

*是否有方法可以检测到文件正在等待删除?



我们已经尝试了第一个选项,只需在HFILE上的WaitForSingleObject()。但Hfile在WaitForSingleObject执行之前总是关闭的,因此WaitForSingleObject总是返回WAIT_FAILED。显然,尝试等待关闭的句柄不起作用。



我可以等待文件所在文件夹的更改通知。但是,一个极端开销密集的kludge到什么是一个问题只有偶尔(在我的测试中,我的Win7 x64 E6600电脑,它通常会在迭代12000+失败 - 在其他机器上,它可以发生,一旦迭代7或15或56或永不)。



我无法辨别明确允许这个以太的CreateFile()参数。无论CreateFile有什么参数,当文件正在等待删除时,打开用于任何访问的文件真的不行。因为我可以看到这个行为在一个XP盒子和一个x64的Win7盒子,我相信这是核心的NTFS行为打算由微软。所以我需要一个解决方案,允许操作系统在我尝试继续之前完成删除,最好是不必要地占用CPU周期,并且没有观察这个文件所在的文件夹(如果可能)的极端开销。 p>

感谢您花时间阅读并发布回复。澄清的问题欢迎!



[1]是的,这个循环返回写失败或无法关闭哪些泄漏,但由于这是一个简单的控制台测试应用程序,应用程序本身退出,并且Windows保证所有句柄在进程完成时被操作系统关闭。所以这里没有泄漏。

  bool DeleteFileNowA(const char * pszFilename)
{
//确定存储临时文件名的路径
char szPath [MAX_PATH];
strcpy(szPath,pszFilename);
PathRemoveFileSpecA(szPath);

//生成一个保证是唯一的临时文件名以容纳待删除的
char szTempName [MAX_PATH];
if(!GetTempFileNameA(szPath,.xX,0,szTempName))
return false;

//将真实文件移动到虚拟文件名
if(!MoveFileExA(pszFilename,szTempName,MOVEFILE_REPLACE_EXISTING))
return false;

//删除队列(当所有句柄(我们的或其他进程)关闭时,OS将删除它)
if(!DeleteFileA(szTempName))
return false;

return true;
}


解决方案

重命名要删除的文件,然后删除呢?



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



编辑 当然,如果你的分析是正确的,文件操作有些异步,问题,您尝试在重命名完成之前删除该文件。但是,然后你可以总是试图删除在后台线程。



编辑#2: 如果汉斯是对的移动可能不会真正帮助,因为您可能无法实际重命名由另一个进程打开的文件。 (但是你可能,我不知道这个。)如果这是真的,我唯一能想出的另一种方法是继续尝试。您必须等待几个毫秒,然后重试。保持超时,放弃当这没有帮助。


Solved:
* Workable Solution: @sbi
* Explanation for what really happens: @Hans
* Explanation for why OpenFile doesn't pass through "DELETE PENDING": @Benjamin

The Problem:
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. (i.e. during the file create 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).

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;
}

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

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.

Questions:
* Is there a way to wait for the delete to complete?
* Is there a way to detect that a file is pending deletion?

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.

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 Win7 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).

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. And since I can see this behavior on both an XP box and on an x64 Win7 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 w/o tying up CPU cycles needlessly, and without the extreme overhead of watching the folder that this file is in (if possible).

Thanks for taking the time to read this and post a response. Clarifying Questions welcome!

[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 app, the app 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;
}

解决方案

Why don't you first rename the file to be deleted, and then delete it?

Use GetTempFileName() to obtain a unique name, 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.

Edit: 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.

Edit #2: 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天全站免登陆