c# - 线程中断后无法删除文件
问题描述
我有点迷失了这个;我已经尝试了我所知道的一切来进行此类操作,但错误仍然存在。
我有一个 FileProcessor 类,它创建一个新线程、执行一些操作等;但是,即使在其中手动调用 Dispose() 和 Thread.Interrupt() 我似乎也无法在使用后删除文件。
首先,我在主线程上使用异步方法执行此代码;现在我已经切换到这个 FileProcessor 的线程,只是想在操作后删除这些文件。
我可以删除一个或两个文件,但是当它到达第三个文件时,它会抛出一个 System.IOEXception
我真的不知道我还能做什么。任何输入表示赞赏。我在 Dispose() 中使用 Worker.Join 并等待线程完成或 GC 结束它 - 但它们都没有发生。
谢谢
我的代码(尽可能减少)Form1:
using System.Collections.Generic;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private bool RestartTimer;
private bool ThreadRunning;
FileProcessor TIFFtoXMLProcessor;
FileProcessor CIP3toTIFFProcessor;
List<string> files;
public Form1()
{
InitializeComponent();
TIFFtoXMLProcessor = new FileProcessor();
RestartTimer = false;
}
private void BeginWork()
{
TIFFtoXMLProcessor.EnqueueFileName(@"C:\test\yourtestfile1.txt");
TIFFtoXMLProcessor.EnqueueFileName(@"C:\test\yourtestfile2.txt");
TIFFtoXMLProcessor.EnqueueFileName(@"C:\test\yourtestfile3.txt");
files = new List<string>(TIFFtoXMLProcessor.fileNamesQueue);
TIFFtoXMLProcessor.eventWaitHandle.Set();
if(TIFFtoXMLProcessor.worker.IsAlive == false)
{
foreach(var item in files)
{
System.IO.File.Delete(item);
}
}
}
}
}
文件处理器类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;
using System.IO;
namespace WindowsFormsApp1
{
class FileProcessor : IDisposable
{
public EventWaitHandle eventWaitHandle { get; private set; }
public Thread worker { get; private set; }
private readonly object locker = new object();
public Queue<string> fileNamesQueue { get; private set; }
public string currConversion { get; private set; }
public bool JobComplete { get; private set; }
private CancellationTokenSource cancelParallelWorker;
public string ColorSeparator { get; private set; }
private readonly TextBox tbStatus;
public string outputFolder { get; private set; }
List<string> filesgoingtorun;
//var AvailableJobsDictionary = new Dictionary<string, List<string>>();
//string nZones, string zWidth, string fzWidth, string lzWidth, string zAreaWidth, string zAreaHeight, double DPI
public FileProcessor()
{
eventWaitHandle = new AutoResetEvent(false);
fileNamesQueue = new Queue<string>();
// Create worker thread
worker = new Thread(Work)
{
IsBackground = true
};
cancelParallelWorker = new CancellationTokenSource();
worker.Start();
}
public void EnqueueFileName(string FileName)
{
// Enqueue the file name
// This statement is secured by lock to prevent other thread to mess with queue while enqueuing file name
lock (locker) fileNamesQueue.Enqueue(FileName);
// Signal worker that file name is enqueued and that it can be processed
//eventWaitHandle.Set();
}
private void Work()
{
List<string> filesToWork = new List<string>();
while (true)
{
string fileName = null;
// Dequeue the file name
lock (locker)
while (fileNamesQueue.Count > 0)
{
fileName = fileNamesQueue.Dequeue();
filesToWork.Add(fileName);
if (fileName == null) return;
}
if (fileNamesQueue.Count == 0 && filesToWork.Count > 0)
{
var tempList = new List<string>(filesToWork);
filesToWork.Clear();
ProcessJob(tempList);
}
}
}
private void ProcessJob(List<string> filesToWork)
{
try
{
JobComplete = true;
switch (currConversion)
{
case "TIF":
{
int j = 0;
foreach (var currJob in filesToWork)
{
//Series of tasks...
j++;
}
eventWaitHandle.WaitOne();
break;
}
}
JobComplete = false;
Dispose();
}
catch (Exception conversionEx)
{
cancelParallelWorker?.Cancel();
}
}
#region IDisposable Members
public void Dispose()
{
// Signal the FileProcessor to exit
EnqueueFileName(null);
// Wait for the FileProcessor's thread to finish
worker.Interrupt();
// Release any OS resources
eventWaitHandle.Close();
}
#endregion
}
}
解决方案
您的代码对于您要执行的操作非常复杂,难怪您在某个地方留下了在不同线程上打开文件的句柄,这会阻止您的代码删除该文件。在无法复制这个问题的情况下,我什至可以开始弄清楚你应该做什么。
但这是我要建议的方法。
您应该使用 Microsoft 的反应式框架(又名 Rx)- NuGetSystem.Reactive.Windows.Forms
并添加using System.Reactive.Linq;
- 然后您可以执行以下操作:
public partial class Form1 : Form
{
private Subject<string> _enqueue = new Subject<string>();
private IDisposable _subscription = null;
public Form1()
{
InitializeComponent();
string ColorSeparator = "42";
int imageRotationNumber = 42;
IObservable<string> query =
from file in _enqueue
from ImageListSorted in Observable.Start(() => ImageBuilder(file, ColorSeparator))
from RotateCMYK in Observable.Start(() => Rotate(ImageListSorted.CMYKmages, imageRotationNumber))
select file;
_subscription = query.Subscribe(f => System.IO.File.Delete(f));
_enqueue.OnNext(@"C:\test\yourtestfile1.txt");
_enqueue.OnNext(@"C:\test\yourtestfile2.txt");
_enqueue.OnNext(@"C:\test\yourtestfile3.txt");
}
private CreateCMYKAndImpositionImageList ImageBuilder(string JobImages, string colorDelimiter)
{
return new CreateCMYKAndImpositionImageList(JobImages, colorDelimiter);
}
private RotateImages Rotate(Dictionary<string, string> imageList, int RotationNumber)
{
return new RotateImages(imageList, RotationNumber);
}
}
现在,我在您的流程中只包含了两个步骤,但您应该能够通过其余步骤继续逻辑。
每一步都是异步运行的,整个事情可以随时通过调用来取消_subscription.Dispose();
。
.Subscribe(f => System.IO.File.Delete(f))
完成所有步骤后才能进入决赛。
因此,只要您避免与线程和任务相关的任何事情,那么它应该运行得非常干净。
推荐阅读
- python - Python中的小费计算器
- docker - Docker 容器的带宽和磁盘空间
- neo4j - 使用密码查询 Neo4j 中关系的属性
- angular - Angular 和 Bootstrap 模板
- javascript - 修改 JQuery 函数以在单击时运行
- php - 为什么我的背景图像在不同的屏幕尺寸上不断变化?
- heroku - 错误:缺少必需的标志:-a,--app APP 应用程序来运行命令
- java - Tomcat 8 无法创建 Java jli.dll
- javascript - 给定一串字母,我如何计算每个字母的出现次数?
- c++ - 在视频 OpenCV C++ 中去除阴影并添加跟踪