线程中断后无法删除文件 [英] Can't delete a file after thread is interrupted

查看:49
本文介绍了线程中断后无法删除文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对这个有点迷茫;我已经尝试了我所知道的一切进行此类操作,但错误仍然存​​在.

I'm kinda lost on this one ; i've tried everything i know for doing such operation and the error persists.

我有一个 FileProcessor 类,它创建一个新线程,执行一些操作等;但是,即使在其中手动调用 Dispose() 和 Thread.Interrupt() 时,我似乎也无法在使用后删除文件.

I've a FileProcessor class that creates a new thread, do some operations, etc ; however, even when manually calling Dispose() inside it and Thread.Interrupt() i can't seem to delete the files after use.

首先,我在主线程上使用异步方法执行此代码;现在我已经切换到使用此 FileProcessor 进行线程处理,只是尝试在操作后删除这些文件.

First i was doing this code using an async method on the main thread ; now i've switched to threading with this FileProcessor, just trying to delete those files after the operation.

我可以删除一两个文件,但是当它到达第三个文件时,它会抛出 System.IOEXception

I can delete one or two files, but when it gets to the third file it throws an System.IOEXception

我真的不知道我还能做什么.任何输入表示赞赏.我在 Dispose() 中使用 Worker.Join 并等待线程完成或 GC 结束它 - 但它们都没有发生过.

I truly don't know what else can i do. Any input is appreciated. I was using Worker.Join inside Dispose() and waiting for the thread to finish or the GC ends it - but neither of em ever happened.

谢谢

我的代码(尽可能减少)表格一:

My code (reduced as possible) 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);
                }
            }
        }
    }
}

FileProcessor 类:

The FileProcessor class:

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
    }

}

推荐答案

对于您要执行的操作,您的代码非常复杂,难怪您在某个地方为在不同线程上打开的文件留下了句柄这会阻止您的代码删除文件.在无法复制这个问题的情况下,我什至可以开始弄清楚你应该做什么.

Your code is insanely complex for what you're trying to do and it's no wonder that somewhere you've left a handle for a file open on a different thread and that's preventing your code from being able to delete the file. Without being able to replicate the issue at this end I can even begin to figure out what you should do.

但这是我要建议的方法.

But here's the approach I'm going to suggest.

你应该使用微软的 Reactive Framework(又名 Rx) - NuGet System.Reactive.Windows.Forms 并添加 using System.Reactive.Linq; - 然后你就可以了像这样:

You should use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive.Windows.Forms and add using System.Reactive.Linq; - then you can do something like this:

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

现在,我只在您的流程中包含了两个步骤,但您应该能够继续执行其余步骤的逻辑.

Now, I've only included two steps in your process, but you should be able to continue the logic through the rest of the steps.

每一步都是异步运行的,可以通过调用_subscription.Dispose();随时取消整个过程.

Each step is run asynchronously and the entire thing can be cancelled anytime by calling _subscription.Dispose();.

最后的 .Subscribe(f => System.IO.File.Delete(f)) 只有在所有步骤都完成后才能被点击.

The final .Subscribe(f => System.IO.File.Delete(f)) can only be hit once all of the steps are complete.

因此,只要您避免与线程和任务相关的任何事情,那么这应该会运行得很干净.

So as long as you avoid anything relating to threading and tasks then this should run quite cleanly.

这篇关于线程中断后无法删除文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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