Reputation: 119
I'm kinda lost on this one ; i've tried everything i know for doing such operation and the error persists.
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.
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.
I can delete one or two files, but when it gets to the third file it throws an System.IOEXception
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.
Thanks
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);
}
}
}
}
}
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
}
}
Upvotes: 1
Views: 293
Reputation: 117027
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.
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.
Each step is run asynchronously and the entire thing can be cancelled anytime by calling _subscription.Dispose();
.
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.
Upvotes: 1