CancellationToken.ThrowIfCancellationRequested() throws an unexpected exception - c#

Can anyone help and determine if this is my error or the unlikely .Net bug?
The code below shows a Main() routine starting 10 tasks, using the DoNothing() method as the underlying method and a SemphoreSlim that will allow 3 tasks to run simultaneously.
Then the Main() waits for a duration of time:
Thread.Sleep(3000);
After the wait we cancel all tasks:
cancel.Cancel();
At which point I expected the .ContinueWith(..) to take over:
doNothingTasks.Add(
Task.Factory.StartNew(() => doNng.DoNothing(canToken), canToken)
.ContinueWith(_ => { Console.WriteLine(..);
}, TaskContinuationOptions.OnlyOnCanceled)
Instead I get an exception on the following line in the DoNothing() routine:
This is unexpected.
Output at exception is:
Can anyone explain???
Complete code:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace TestAsync
{
class Program
{
private static readonly SemaphoreSlim Broker = new SemaphoreSlim(3);
static void Main(string[] args)
{
var doNothingTasks = new List<Task>();
using (var cancel = new CancellationTokenSource())
{
var canToken = cancel.Token;
for (var i = 0; i < 10; ++i)
{
var doNng = new TestCancellationToken(i);
doNothingTasks.Add(
Task.Factory.StartNew(() =>
doNng.DoNothing(canToken), canToken)
.ContinueWith(_ => { Console.WriteLine(
$"{DateTime.Now:HH:mm:ss.ffff}. " +
$"{new string('.', 25)} {doNng.Name} " +
$"WAS CANCELLED {new string('.', 10)}");
}, TaskContinuationOptions.OnlyOnCanceled)
);
}
Thread.Sleep(3000);
cancel.Cancel();
try
{
Task.WaitAll(doNothingTasks.ToArray());
}
catch (AggregateException ae)
{
var fae = ae.Flatten();
foreach (var ex in fae.InnerExceptions)
Console.WriteLine($"{DateTime.Now:HH:mm:ss.ffff}. " +
$"{ex.GetType().Name}: {ex.Message}");
}
Console.WriteLine("Done.");
Console.ReadKey();
}
}
class TestCancellationToken
{
private readonly Random _rnd;
public int Name { get; }
public TestCancellationToken(int inx)
{
_rnd = new Random(inx);
Name = inx;
}
public void DoNothing(CancellationToken canToken)
{
for (var i = 0; ; ++i)
{
if (canToken.IsCancellationRequested)
canToken.ThrowIfCancellationRequested();
Broker.Wait();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.ffff}. " +
$"Test {Name} round: {i}, aquire time");
var sleepPeriod = _rnd.Next(750) + 50;
Thread.Sleep(sleepPeriod);
Broker.Release();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.ffff}. " +
$"Test {Name} round: {i}, release time: {sleepPeriod}");
}
}
}
}
}

Related

cannot convert from System.Collections.Generic.List<sales.ScanInfo> to System.Collections.Generic.IEnumerable<System.Threading.Tasks.Task>

I have the following code inside my c# console application, where i am calling a method called getInfo in parallel using WhenAll() method, as follow:-
class Program
{
static int concurrentrequests = int.Parse(ConfigurationManager.AppSettings["ConcurrentRequests"]);
static SemaphoreSlim throttler = new SemaphoreSlim(initialCount: concurrentrequests);
private static ScanInfo getInfo(string website)
{
throttler.Wait();
ScanInfo si = new ScanInfo();
int counter = 1;
try
{
//code goes here..
}
catch (Exception e)
{
//code goes here
}
finally
{
throttler.Release();
}
}
return si;
}
static void Main(string[] args)
{
Marketing ipfd = new Marketing();
try
{
using (WebClient wc = new WebClient()) // call the PM API to get the account id
{
//code goes here
}
}
catch (Exception e)
{
}
var tasks = ipfd.companies.Select(c => getInfo(c.properties.website.value)).ToList();
var results = Task.WhenAll(tasks);
//code goes here..
}
}
but i am getting this exception:-
Argument 1: cannot convert from
System.Collections.Generic.List<Sales.ScanInfo> to
System.Collections.Generic.IEnumerable<System.Threading.Tasks.Task>
so can anyone advice why i am getting this error?
var tasks = ipfd.companies.Select(c => getInfo(c.properties.website.value)).ToList();
var results = Task.WhenAll(tasks);
tasks contains the results. YOu dont have to do any waiting at all. What make syou think you do. So just do
var results = ipfd.companies.Select(c => getInfo(c.properties.website.value)).ToList();

C# Multithreading for three threads working in parallel and sending data to each other and working in order

I have a C# windows form program that uses three threads.
*The first thread is responsible for reading files from input folder and reading all text from each file then send data as string to the second thread using a Queue.
*The second thread is responsible on parsing the string got from the first thread, if the string was a number then send this number to the third thread also using a Queue.
*The third thread is responsible on creating file for the number got from thread 2.
Also I should have a Timer that runs thread 1 every 4 seconds for example until pressing stop.( should thread 2 and thread 3 when thread 1 runs after 4 seconds ?)
Note That the three threads should be running in parallel and should be in the correct order Thread 1 then Thread 2 then Thread 3 and should be getting and sending data for each other.
Below is an image for what i described below and some of the code that I used in my program.
Please I want your help I'm stuck in this ....
Code is :
form1.cs Class
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mltithreading
{
public partial class Form1 : Form
{
public ConcurrentQueue<string> _queue = new ConcurrentQueue<string>();
public Queue<string> Queue1result = new Queue<string>();
public Queue<string> TestQueue = new Queue<string>();
public Queue<string> Queue2result = new Queue<string>();
public Form1()
{
InitializeComponent();
}
/* private Timer timer1;
public void InitTimer()
{
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 2000; // in miliseconds
timer1.Start();
} */
private void timer1_Tick(object sender, EventArgs e)
{
isonline();
}
public void isonline()
{
//
// The user selected a folder and pressed the OK button.
// We print the number of files found.
//
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
MessageBox.Show(files[0]);
var a = files[1];
var dir = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
FileInfo[] f = dir.GetFiles();
foreach (System.IO.FileInfo fi in f)
{
Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
MessageBox.Show("Files found: " + files.Length.ToString(), "Message");
}
private void button1_Click(object sender, EventArgs e)
{
DialogResult result = folderBrowserDialog1.ShowDialog();
if (result == DialogResult.OK)
{
//
// The user selected a folder and pressed the OK button.
// We print the number of files found.
//
textBox1.Text = folderBrowserDialog1.SelectedPath;
/* try
{
string[] files = Directory.GetFiles(folderBrowserDialog1.SelectedPath);
var dir = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
var output = folderBrowserDialog2.SelectedPath;
FileInfo[] f = dir.GetFiles();
Queue<FileInfo> Q = new Queue<FileInfo>(f);
while (Q.Count > 0)
{
FileInfo current = Q.Dequeue();
Console.WriteLine(current);
// Process 'current'
}
foreach (System.IO.FileInfo fi in f)
{
Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
MessageBox.Show("Files found: " + files.Length.ToString(), "Message");
}
catch (Exception excep)
{
Console.WriteLine("An error occurred: '{0}'", excep);
} */
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
DialogResult result = folderBrowserDialog2.ShowDialog();
if (result == DialogResult.OK)
{
//
// The user selected a folder and pressed the OK button.
// We print the number of files found.
//
textBox2.Text = folderBrowserDialog2.SelectedPath;
}
}
private void button3_Click(object sender, EventArgs e)
{
string input = folderBrowserDialog1.SelectedPath;
string output = folderBrowserDialog2.SelectedPath;
var result = Thread1Start(input, output);
Console.WriteLine("Is thread Still Running :{0}", result);
//var firstThread = new Thread1();
var secondThread = new Thread2();
var thirdThread = new Thread3();
//Thread thread = new Thread(() => th.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath));
//Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath); });
//Thread thread3 = new Thread(() =>second.test(valueQueue));
Thread thread2 = new Thread(delegate() { Queue2result = secondThread.test(TestQueue); });
Thread thread3 = new Thread(() => thirdThread.CreateFiles(Queue2result,output));
//Thread thread5 = new Thread(second.run);
//thread1.Start();
// thread1.Join();
thread2.Start();
//thread2.Join();
thread3.Start();
//thread1.Start();
//thread1.Join();
//thread2.Start();
//thread1.Join(TimeSpan.Zero);
//Console.WriteLine(thread1.Join(TimeSpan.Zero));
// new System.Threading.Timer (ThreadTimer, "Thread 1 Started working...", 5000, 1000);
}
private void button4_Click(object sender, EventArgs e)
{
}
/* public void ThreadTimer (object data)
{
string input = folderBrowserDialog1.SelectedPath;
string output = folderBrowserDialog2.SelectedPath;
var result = Thread1Start(input, output);
Console.WriteLine("Is thread Still Running :{0}",result);
}
*/
public bool Thread1Start(string input, string output)
{
var firstThread = new Thread1();
Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(input, output); });
TestQueue = Queue1result;
thread1.Start();
Console.WriteLine("thread 1 start");
var state = thread1.Join(TimeSpan.Zero);
var secondThread = new Thread2();
var thirdThread = new Thread3();
//Thread thread = new Thread(() => th.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath));
//Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(folderBrowserDialog1.SelectedPath, folderBrowserDialog2.SelectedPath); });
//Thread thread3 = new Thread(() =>second.test(valueQueue));
Thread thread2 = new Thread(delegate() { Queue2result = secondThread.test(Queue1result); });
Thread thread3 = new Thread(() => thirdThread.CreateFiles(Queue2result, output));
//Thread thread5 = new Thread(second.run);
//thread1.Start();
// thread1.Join();
thread2.Start();
//thread2.Join();
thread3.Start();
return state;
}
}
}
Thread1.cs class
here using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mltithreading
{
class Thread1
{
public void run()
{
while (true)
{
int iterations = 10;
try
{
for (int i = 0; i < iterations; i++)
{
Console.WriteLine("From Thread 1");
Thread.Sleep(2000);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public Queue<string> Readfiles(string inputDirectoryPath, string outputDirectoryPath)
{ Queue<string> thread1Queue = new Queue<string>();
try
{
var dir = new DirectoryInfo(inputDirectoryPath);
FileInfo[] f = dir.GetFiles();
foreach (System.IO.FileInfo fi in f)
{
var filePath = fi.DirectoryName + "\\" + fi.Name;
//File.Copy(filePath, outputDirectoryPath + "\\" + fi.Name);
// Open the file to read from.
string readText = File.ReadAllText(filePath);
thread1Queue.Enqueue(readText);
Console.WriteLine(readText);
Console.WriteLine("thread 1 call read files method ");
//Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
}
catch (Exception excep)
{
Console.WriteLine("An error occurred: '{0}'", excep);
}
return thread1Queue;
}
}
}
Thread2.cs class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Mltithreading
{
class Thread2
{
public void run()
{
while (true)
{
int iterations = 10;
try
{
for (int i = 0; i < iterations; i++)
{
Console.WriteLine("From Thread 2");
Thread.Sleep(2000);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public Queue<string> test(Queue<string> list)
{
Queue<string> thread2Queue = new Queue<string>();
while (list.Count > 0)
{
try
{
var a = list.Dequeue();
Console.WriteLine(a);
int j;
if (Int32.TryParse(a, out j))
{
Console.WriteLine("parsed the string {0} to integer and sent to thread 3", j);
thread2Queue.Enqueue(a);
}
else
Console.WriteLine("String could not be parsed to integer.");
Console.WriteLine("thread 2 parsing string from thread 1");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
return thread2Queue;
}
}
}
Thread3.cs Class
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Mltithreading
{
class Thread3
{
public void run()
{
while (true)
{
int iterations = 10;
try
{
for (int i = 0; i < iterations; i++)
{
Console.WriteLine("From Thread 3");
Thread.Sleep(2000);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public void CreateFiles(Queue<string> list, string outputDirectoryPath)
{
while (list.Count > 0)
{
string format = "MM-dd-yyyy--HH-mm-ss";
DateTime date = DateTime.Now;
string filename = date.ToString(format);
string file = outputDirectoryPath + "\\" + filename + ".txt";
var a = list.Dequeue();
FileInfo fi = new FileInfo(file);
if (!fi.Exists)
{
fi.Create().Dispose();
System.IO.File.WriteAllText(file,a);
Console.WriteLine("creating new text file {{0}}",file);
}
else
{
Console.WriteLine("file already exists");
}
Console.WriteLine(a);
Console.WriteLine("Thread 3 creating File with date name");
Console.WriteLine(date.ToString(format));
}
}
}
}
Thank you very much for your help .
I won´t comment on all, there´s too much stuff to talk about, but let´s have a look at your first thread.
Thread thread1 = new Thread(delegate() { Queue1result = firstThread.Readfiles(input, output); });
This line will create a thread that will replace the existing instance in your field Queue1Result (have a look at naming conventions, please!) once after reading some files (if existing). If executed again, The existing queue goes out of scope and will be replaced with a new one, probably not what you want to do.
You need to create those queue instances just once (type to use is ConcurrentQueue), those should then be used as a parameter running the thread procedure. So, redeclare the queues to readonly ConcurrentQueue to create the instances for your fields(give them a good "speaking" name, btw).
public readonly ConcurrentQueue<string> _textFromFilesQueue = new ConcurrentQueue<string>();
Once started, you want to regularly look after files again, so your code has to contain a loop.
This loop to be executed should be terminable from outside / other threads using a CancellationToken. Lets add a CancellationTokenSource to Form 1:
public CancellationTokenSource CancellationTokenSource { get; set; }
Your execution code for the first thread could / should look like this:
public void Readfiles(string inputDirectoryPath, string outputDirectoryPath, ConcurrentQueue<string> queue, CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
var dir = new DirectoryInfo(inputDirectoryPath);
FileInfo[] f = dir.GetFiles();
foreach (System.IO.FileInfo fi in f)
{
var filePath = Path.Combine(fi.DirectoryName, fi.Name);
//File.Copy(filePath, outputDirectoryPath + "\\" + fi.Name);
// Open the file to read from.
string textFromFile = File.ReadAllText(filePath);
queue.Enqueue(textFromFile);
Console.WriteLine(textFromFile);
Console.WriteLine("thread 1 call read files method ");
//Console.WriteLine("{0}: {1}: {2}", fi.Name, fi.LastAccessTime, fi.Length);
}
Thread.Sleep(TimeSpan.FromSeconds(5));
}
catch (Exception excep)
{
Console.WriteLine("An error occurred: '{0}'", excep);
Throw excep;
}
}
}
Do not build up a path by concatenating strings, use Path.Combine instead. Also, exceptions that happened should just be rethrown to ensure correct handling from other threads / tasks.
I would recommend using the TPL mechanisms instead of threads, it grants the system more flexibility in handling the tasks to be executed in a parallel manner. Have a look here : https://msdn.microsoft.com/de-de/library/dd460717(v=vs.110).aspx
So, creating and executing this task:
CancellationTokenSource = new CancellationTokenSource();
Task task = new Task(() => Readfiles(input, output, _textFromFilesQueue, CancellationTokenSource.Token));
task.Start();
Stopping the task:
CancellationTokenSource.Cancel();
Be sure not to overwrite the TokenSource without calling Cancel(), else you are losing the ability to stop the tasks that have already started...
EDIT: If you really need to ignore TPL, here is the example to execute the reading method with a thread:
Thread thread = new Thread(new ThreadStart(() => Readfiles(input, output, _textFromFilesQueue, CancellationTokenSource.Token)));
thread.Resume();
Use very simple and clear code:
var inputTexts = new BlockingCollection<string>();
var inputNumbers = new BlockingCollection<string>();
var readFiles = Task.Run(() =>
{
try
{
foreach (var file in Directory.EnumerateFiles("path", "searchPattern"))
{
string text = File.ReadAllText(file);
inputTexts.Add(text);
}
}
finally { inputTexts.CompleteAdding(); }
});
var processNumbers = Task.Run(() =>
{
try
{
foreach (var text in inputTexts.GetConsumingEnumerable())
{
int result;
if (int.TryParse(text, out result))
inputNumbers.Add(text);
}
}
finally { inputNumbers.CompleteAdding(); }
});
var createFiles = Task.Run(() =>
{
foreach (var number in inputNumbers.GetConsumingEnumerable())
{
string path = ""; // set fileName
File.WriteAllText(path, number);
}
});
Task.WaitAll(readFiles, processNumbers, createFiles);
It guarantees the execution in the correct order.
You can easily add cancellation using CancellationTokenSource.
Ok. Here is a working application that uses threads and timer.
It is assumed that execution all threads is faster than the timer interval.
New threads starts with each timer tick. The old threads will continue to work if they have not yet ended.
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
Button stopButton;
System.Windows.Forms.Timer timer;
public Form1()
{
//InitializeComponent();
stopButton = new Button { Parent = this, Text = "Stop" };
stopButton.Click += StopButton_Click;
timer = new System.Windows.Forms.Timer();
timer.Interval = 1000;
timer.Tick += Timer_Tick;
timer.Start();
Text = "Start";
}
private void StopButton_Click(object sender, EventArgs e)
{
timer.Stop();
Text = "Stop";
}
private void Timer_Tick(object sender, EventArgs e)
{
var inputTexts = new BlockingCollection<string>();
var inputNumbers = new BlockingCollection<string>();
var readFiles = new Thread(() =>
{
try
{
foreach (var file in Directory.EnumerateFiles("./Folder", "*.txt"))
{
string text = File.ReadAllText(file);
inputTexts.Add(text);
}
}
finally { inputTexts.CompleteAdding(); }
});
var processNumbers = new Thread(() =>
{
try
{
foreach (var text in inputTexts.GetConsumingEnumerable())
{
int result;
if (int.TryParse(text, out result))
inputNumbers.Add(text);
}
}
finally { inputNumbers.CompleteAdding(); }
});
var createFiles = new Thread(() =>
{
int counter = 0;
foreach (var number in inputNumbers.GetConsumingEnumerable())
{
File.WriteAllText("./Folder2/" + counter + ".txt", number);
counter++;
}
});
readFiles.Start();
processNumbers.Start();
createFiles.Start();
readFiles.Join();
processNumbers.Join();
createFiles.Join();
}
}
}

C# multithreading code not hitting break point

Please look at the sample code below, When I place a break point inside "testmethod" and run the application, it is not hitting the breakpoint. Is this code good?
static void Main(string[] args)
{
Thread[] testthreads = new Thread[3];
List<int> testdata = new List<int>();
testdata.Add(1);
testdata.Add(2);
testdata.Add(3);
int i = 0;
foreach (int data in testdata)
{
testthreads[i] = new Thread(new ThreadStart(() => testmethod(data)));
testthreads[i].Name = string.Format("Working Thread: {0}", data);
i++;
}
}
static void testmethod(int i)
{
try
{
//DataTable dt = DB.GetData(i);
if (dt.Count > 0)
{
Console.WriteLine("Count: {0}", dt.Count);
}
}
catch (Exception ex)
{
throw ex;
}
}
I tried another method and it always returns the Name of first input.
Method 2:
static void Main(string[] args)
{
List testdata = new List();
testdata.Add(111111);
testdata.Add(222222);
testdata.Add(333333);
foreach (int data in testdata)
{
new Thread(delegate()
{
DataTable dt = DB.GetData(data);
if (dt.Count > 0)
{
Console.WriteLine("Name: {0}", dt.Rows[0]["Name"];);
}
// Signal the CountdownEvent.
countdownEvent.Signal();
}).Start();
}
// Wait for workers.
countdownEvent.Wait();
Console.WriteLine("Finished.");
}
Output:
Name: JULIE
Name: JULIE
Name: JULIE
Always returns the value(Name) of 111111
You need to start the thread.
testthreads[i] = new Thread(new ThreadStart(() => testmethod(data)));
testthreads[i].Name = string.Format("Working Thread: {0}", data);
testthreads[i].Start();

My C# multi-threaded console application seems to not be multithreaded

Here's my C# console program that uses Powerpoint to convert ppt files to folders of pngs. This is supposed to be an automated process that runs on its own server.
I expect that as soon as a thread creates an image from a file, it should immediately remove the images and the source file.
The actual behavior is that, if five threads are running, it'll wait for five folders of images to be created before any thread can move any files. I'm able to see the images being created, and compare that with the Console readout, so I can see that a thread isn't trying to move the file.
Only after all the other threads have made their images, will any thread try to move the files. I suspect this is wrong.
This is an Amazon EC2 Medium instance, and it appears to max out the CPU, so five threads might be too much for this.
I also find that I can hardly use Windows Explorer while this program is running.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using Microsoft.Office.Core;
using PowerPoint = Microsoft.Office.Interop.PowerPoint;
using System.Diagnostics;
using System.Timers;
namespace converter
{
class Program
{
public static int threadLimit=0;
public static int currThreads = 0;
static void Main(string[] args)
{
var inDir = args[0];
var outDir = args[1]+"\\";
var procDir = args[2]+"\\";
Int32.TryParse(args[3],out threadLimit);
Thread[] converterThreads = new Thread[threadLimit];
while (true)
{
System.Threading.Thread.Sleep(1000);
var filePaths = Directory.GetFiles(inDir, "*.*", SearchOption.AllDirectories).Where(s => s.EndsWith(".pptx") && !s.Contains("~$") || s.EndsWith(".ppt") && !s.Contains("~$"));
var arrPaths = filePaths.ToArray();
for(var i=0; i< arrPaths.Length; i++)
{
if (currThreads < threadLimit && currThreads < arrPaths.Length)
{
Console.WriteLine("currThreads= " + currThreads + " paths found= " + arrPaths.Length);
try
{
var fileNameWithoutExtension = arrPaths[currThreads].Replace(inDir, "").Replace(".pptx", "").Replace(".ppt", "").Replace("\\", "");
var filenameWithExtension = arrPaths[currThreads].Substring(arrPaths[currThreads].LastIndexOf("\\") + 1);
var dir = arrPaths[currThreads].Replace(".pptx", "").Replace(".ppt", "");
Conversion con = new Conversion(arrPaths[currThreads], dir, outDir, procDir, filenameWithExtension, fileNameWithoutExtension);
converterThreads[i] = new Thread(new ThreadStart(con.convertPpt));
converterThreads[i].Start();
Console.WriteLine(converterThreads[i].ManagedThreadId + " is converting " + fileNameWithoutExtension);
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to convert {0} ", arrPaths[i]) + e);
}
}
}
for (var i = 0; i < converterThreads.Length; i++)
{
if (converterThreads[i] != null)
{
if (!converterThreads[i].IsAlive)
{
converterThreads[i].Abort();
converterThreads[i].Join(1);
Console.WriteLine("thread " + converterThreads[i].ManagedThreadId + " finished, "+currThreads+" remaining");
converterThreads[i] = null;
}
}
}
if (currThreads == 0)
{
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
}
}
class Logger{
static void toLog(String msg)
{
//TODO: log file
}
}
class Conversion{
static int numberOfThreads=0;
String input;
String output;
String outDir;
String process;
String nameWith;
String nameWithout;
int elapsedTime;
System.Timers.Timer time;
public Conversion(String input, String output, String outDir, String processDir, String nameWith, String nameWithout)
{
this.input = input;
this.output = output;
this.outDir = outDir;
process = processDir;
this.nameWith = nameWith;
this.nameWithout = nameWithout;
numberOfThreads++;
Console.WriteLine("number of threads running: " + numberOfThreads);
Program.currThreads = numberOfThreads;
time = new System.Timers.Timer(1000);
time.Start();
time.Elapsed += new ElapsedEventHandler(OnTimedEvent);
elapsedTime = 0;
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
elapsedTime++;
}
public void convertPpt()
{
var app = new PowerPoint.Application();
var pres = app.Presentations;
try
{
var file = pres.Open(input, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);
file.SaveAs(output, Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsPNG, MsoTriState.msoTrue);
file.Close();
app.Quit();
Console.WriteLine("file converted " + input);
}
catch (Exception e)
{
Console.WriteLine("convertPpt failed");
}
moveFile();
moveDir();
}
public void moveFile()
{
Console.WriteLine("moving" + input);
try
{
System.Threading.Thread.Sleep(500);
Console.WriteLine(string.Format("moving {0} to {1}", input, process + nameWith));
if (File.Exists(process + nameWith))
{
File.Replace(input, process + nameWith, null);
}
else
{
File.Move(input, process + nameWith);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the file {0} ", input) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
}
public void moveDir()
{
Console.WriteLine("moving dir " + output);
try
{
System.Threading.Thread.Sleep(500);
Console.WriteLine(string.Format("moving dir {0} to {1} ", output, outDir + nameWithout));
if (Directory.Exists(outDir + nameWithout))
{
Directory.Delete(outDir + nameWithout, true);
}
if (Directory.Exists(output))
{
Directory.Move(output, outDir + nameWithout);
}
}
catch (Exception e)
{
Console.WriteLine(string.Format("Unable to move the directory {0} ", output) + e);
try
{
foreach (Process proc in Process.GetProcessesByName("POWERPNT"))
{
proc.Kill();
}
}
catch (Exception e3)
{
}
}
finally
{
numberOfThreads--;
Program.currThreads = numberOfThreads;
Console.WriteLine("took " + elapsedTime + "seconds");
}
}
}
}
Every 1000ms you get a list of files in inDir and potentially start a thread to process each file. You have very complex logic surrounding whether or not to start a new thread, and how to manage the lifetime of the thread.
The logic is too complex for me to spot the error without debugging the code. However, I would propose an alternative.
Have a single thread watch for new files and place the file path into a BlockingCollection of files for processing. That thread does nothing else.
Have N additional threads that retrieve file paths from the BlockingCollection and process them.
This is known as a Producer / Consumer pattern and is ideal for what you are doing.
The example code at the bottom of the linked MSDN page shows an implementation example.
On a side note, you are catching and swallowing Exception e3. Don't catch something you will not handle, it hides problems.

JavaScript Queue function equivalent in C#

I have a JavaScript code that I want to bring the idea into my C# project.
This code brings multiple function call into a single management delayed call.
Here is the JavaScript code:
var ArgumentsCollection = [] ;
var to_TimeOut = null ;
function QueueWorkRunOnce(Argument) {
clearTimeout(to_TimeOut);
ArgumentsCollection.push(Argument) ;
to_TimeOut = setTimeout(/* delegate */ function(){
Worker(ArgumentsCollection);
//Reset ArgumentsCollection
ArgumentsCollection = [] ;
},/*Delay in ms*/ 1000 );
}
function Worker(Collection){
alert(Collection.join(" ")) ;
}
onload = function(){
QueueWorkRunOnce("Hi")
//Some other stuff
QueueWorkRunOnce("There")
//Some other stuff
QueueWorkRunOnce("Hello")
QueueWorkRunOnce("World")
//after Xms + 1000ms Will alert("Hi There Hello World") ;
}()
Here's a rough translation to get you started:
var worker = new Action<IEnumerable<string>>(collection =>
{
Console.WriteLine(string.Join(" ", collection));
});
var args = new List<string>();
var timer = new Timer(state =>
{
worker(args);
//Reset args
args.Clear();
});
var queueWorkRunOnce = new Action<string>(arg =>
{
args.Add(arg);
timer.Change(/*Delay in ms*/ 1000, Timeout.Infinite);
});
queueWorkRunOnce("Hi");
//Some other stuff
queueWorkRunOnce("There");
//Some other stuff
queueWorkRunOnce("Hello");
queueWorkRunOnce("World");
Console.ReadKey();
Making this thread-safe is left as an exercise for the reader.
Here is the same code modified.. Work for me
if anyone can contribuete an thread safe version that will be great.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace QueueWorkRunOnce {
public class Test {
public static void worker(List<string> collection) {
Console.WriteLine(string.Join(" ", collection.ToArray()));
}
public static List<string> args = new List<string>();
public Timer timer = new Timer(state => {
worker(args);
args.Clear();
});
public void queueWorkRunOnce(string arg){
args.Add(arg);
timer.Change(/*Delay in ms*/ 1000, Timeout.Infinite);
}
public Test() {
Console.WriteLine("new Test");
queueWorkRunOnce("Hi");
//Some other stuff
queueWorkRunOnce("There");
//Some other stuff
queueWorkRunOnce("Hello");
queueWorkRunOnce("World");
}
}
class Program {
static void Main(string[] args) {
new Test();
Thread.Sleep(3000);
new Test();
Console.ReadKey();
}
}
}

Categories