【问题标题】:What happens if an application is closed while a thread of ThreadPool is writing a file?如果 ThreadPool 的一个线程在写文件时关闭了应用程序会发生什么?
【发布时间】:2015-02-19 14:56:58
【问题描述】:

假设您使用ThreadPool 执行一些操作并假设每个操作都写入文件。 ThreadPool的所有线程都是后台线程,所以在关闭应用程序时会被终止。如果在ThreadPool 的线程正在向磁盘写入文件时关闭应用程序会发生什么?

【问题讨论】:

  • 它会关闭文件的文件句柄并停止写入,可能会导致文件损坏。你试过这样做吗?
  • 我应该通过写一个大文件来验证会发生什么。
  • 结果很可能因使用的文件系统而异。 FAT 将显示 NTFS 以外的其他结果。
  • 一般来说,如果您发现自己需要回答此类问题(这本身很有用,请不要误会我的意思),这可能表明您应该将设计更改为明显的正确,而不是依赖框架的优点。换句话说,如果您必须确保操作完成,请不要使用后台线程——或者假设您的应用程序可以随时关闭并使其文件损坏,并在启动时相应地处理这种情况。

标签: c# .net multithreading threadpool background-thread


【解决方案1】:

操作系统将关闭文件句柄作为终止进程的一部分。

  • 任何挂起的异步 I/O 都将被取消
  • 写入缓冲区中未刷新的任何数据都会丢失

【讨论】:

    【解决方案2】:

    阅读 Foreground and Background threads 上的 MSDN 文章

    ThreadPool 线程是后台线程。来自文章:

    当运行时因为进程关闭而停止后台线程时,线程中不会抛出异常。

    线程只是停止。它执行一条指令,从不执行下一条。 FileStream 将作为 CLR 清理的一部分关闭。

    【讨论】:

    • CLR 不会关闭文件。它是执行此操作的底层操作系统。
    • 如果进程正常终止,则将调用终结器:参见blog.stephencleary.com/2009/08/finalizers-at-process-exit.html。 FileStream 的终结器关闭底层文件句柄。
    • 只有当实例无法访问时,Finalizers 才会作为垃圾回收的一部分被调用。当 ThreadPool 线程正在使用它编写时,FileStream 怎么会无法访问?
    • 一个简单的演示应用表明 FileStream 在终止之前确实被 CLR 关闭。我在 ThreadPool 上启动了一个新的工作项,它打开一个文件并等待一秒钟,并且有一个试图关闭文件的终结器。应用程序在那一秒内终止。尝试关闭该终结器中的文件会导致 ObjectDisposedException,指示 CLR 已释放 FileStream 对象。还是我误解了什么?
    • 我也刚查过。我用静态场测试了它。终结器在 Winforms 应用程序中被调用,但是当使用关闭按钮关闭控制台应用程序时,它不会被调用。你的回答似乎也是正确的。 +1
    【解决方案3】:

    您可以通过调用Environment.Exit(0)Environment.Exit(1) 方法轻松尝试这种情况(成功退出并退出错误)。我认为该文件的所有句柄都将被删除,并且已写入磁盘的唯一数据将保留,而不会刷新缓冲区。

    在整个过程中,文件可能会因为一些奇怪的错误(如 The file is being used by another process)而变得无法访问,或者在退出进程时出现错误。

    【讨论】:

    • 传递给.Exit() 的参数无关紧要;在这两种情况下,应用程序都会正常终止(意味着finally-blocks 和终结器将运行)。在您进行实验时,请尝试Environment.FailFast(),因为与Exit() 不同,它不是优雅的终止,并且会绕过终结器。请注意,刷新缓冲区可以在终结器中完成,但 BCL 类通常不会(这很遗憾,因为操作系统无论如何都会关闭句柄,这是终结器唯一的附加值有)。
    猜你喜欢
    • 1970-01-01
    • 2012-08-06
    • 2020-08-31
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多