I am developing a proof of concept app that factors a list of numbers using tasks and a semaphore, currently I have a List of Tasks,List<Task>, that take a FactorNumberClass and then calculate the factors of the specific number within the FactorNumberClass this currently works correctly. With each Task T, I have a ContinueWith task that updates the progress of the total numbers factored, the average time for factoring, and updates a progress bar with the value of (Numbers successfully factored)/(Total numbers to be factored). When factoring these Tasks enter a SemaphoreSlim.Wait(cancelToken) that limits the current factoring to 5 active Tasks. Lastly I have a ContinueWhenAll that logs when all tasks have completed. Assuming no cancellation, this all works as I intend.
The problem arises when I attempt to cancel the Tasks, I can not detect whether or not the task has been cancelled and therefore can not make an accurate determination on whether the number has been successfully factored or if it was cancelled. How can I detect whether or not the parent task was cancelled or ran to completion?
Cancellation Token Definition:
public static CancellationTokenSource tokenSource = new CancellationTokenSource();
public static CancellationToken ct = tokenSource.Token;
Factor Class Code:
public class FactorNumberClass
{
public FactorNumberClass()
{
}
public FactorNumberClass(int num, int threadnum)
{
this.number = num;
this.threadNumber = threadnum;
}
public List<int> factors = new List<int>();
public int number;
public int max;
public int threadNumber;
}
Factoring Method:
public void Factor(FactorNumberClass F, CancellationToken token)
{
LogtoStatusText("Thread: " + F.threadNumber + " Trying to enter semaphore");
try
{
ASemaphore.Wait(ct);
F.max = (int)Math.Sqrt(F.number); //round down
for (int factor = 1; factor <= F.max; ++factor)
{ //test from 1 to the square root, or the int below it, inclusive.
if (F.number % factor == 0)
{
F.factors.Add(factor);
if (factor != F.number / factor)
{
F.factors.Add(F.number / factor);
}
}
}
F.factors.Sort();
Thread.Sleep(F.number * 300);
LogtoStatusText("Task: " + F.threadNumber + " Completed - Factors: " + string.Join(",", F.factors.ToArray()));
LogtoStatusText("Thread: " + F.threadNumber + " Releases semaphore with previous count: " + ASemaphore.Release());
}
catch (OperationCanceledException ex)
{
LogtoStatusText("Thread: " + F.threadNumber + " Cancelled.");
}
finally
{
}
}
Method that starts the processing:
public void btnStart_Click(object sender, RoutedEventArgs e)
{
Task T;
List<Task> TaskList = new List<Task>();
LogtoStatusText("**** Begin creating tasks *****");
s1.Start();
AProject.FactorClassList.ForEach((f) =>
{
T = new Task(((x) => { OnUIThread(() => { RunningTasks++; }); Factor(f, ct); }), ct);
T.ContinueWith((y) =>
{
if (y.IsCompleted)
{
AProject.TotalProcessedAccounts++;
AProject.AverageProcessTime = (((Double)AProject.TotalProcessedAccounts / s1.ElapsedMilliseconds) * 1000);
}
OnUIThread(() => { RunningTasks--; });
OnUIThread(() => { UpdateCounts(AProject); });
});
TaskList.Add(T);
});
try
{
Task.Factory.ContinueWhenAll(TaskList.ToArray(), (z) => { LogtoStatusText("**** Completed all Tasks *****"); OnUIThread(() => { UpdateCounts(AProject); }); });
}
catch (AggregateException a)
{
// For demonstration purposes, show the OCE message.
foreach (var v in a.InnerExceptions)
LogtoStatusText("msg: " + v.Message);
}
LogtoStatusText("**** All tasks have been initialized, begin processing *****");
TaskList.ForEach(t => t.Start());
}
Release the semaphore in the finally block so that it is always properly released. No need to detect cancellation.
Also, side-effects buried in log messages are not good style:
LogtoStatusText("..." + ASemaphore.Release());
I only found this through text search. Would have never noticed the mistake otherwise.
Using a cancellation token:
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main()
{
var tokenSource2 = new CancellationTokenSource();
CancellationToken ct = tokenSource2.Token;
var task = Task.Factory.StartNew(() =>
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
bool moreToDo = true;
while (moreToDo)
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
}
}, tokenSource2.Token); // Pass same token to StartNew.
tokenSource2.Cancel();
// Just continue on this thread, or Wait/WaitAll with try-catch:
try
{
task.Wait();
}
catch (AggregateException e)
{
foreach (var v in e.InnerExceptions)
Console.WriteLine(e.Message + " " + v.Message);
}
finally
{
tokenSource2.Dispose();
}
Console.ReadKey();
}
}
https://msdn.microsoft.com/en-us/library/dd997396%28v=vs.110%29.aspx
I finally found the solution I was looking for that would allow me to launch (Start()) all of my Task objects, run them through a semaphoreslim, observe a CancellationToken, and then detect if the Task was cancelled or had completed normally. In this case a Task would only "complete normally" if it had entered the semaphore and begun processing before the CancellationTokenSource.Cancel() was fired.
This answer: Elegantly handle task cancellation pushed me in the correct direction. I ended up catching the OperationCancelledException, logging it, and then re-throwing it, to be examined within the ContinueWith Task
Here is the updated code which solved my issue
Factor Class:
private void Factor(FactorNumberClass F)
{
LogtoStatusText("Thread: " + F.threadNumber + " Trying to enter semaphore");
try
{
ASemaphore.Wait(ct);
F.max = (int)Math.Sqrt(F.number); //round down
for (int factor = 1; factor <= F.max; ++factor)
{ //test from 1 to the square root, or the int below it, inclusive.
if (F.number % factor == 0)
{
F.factors.Add(factor);
if (factor != F.number / factor)
{
F.factors.Add(F.number / factor);
}
}
}
F.factors.Sort();
Thread.Sleep(F.number * 300);
LogtoStatusText("Task: " + F.threadNumber + " Completed - Factors: " + string.Join(",", F.factors.ToArray()));
LogtoStatusText("Thread: " + F.threadNumber + " Releases semaphore with previous count: " + ASemaphore.Release());
}
catch
{
LogtoStatusText("Thread: " + F.threadNumber + " Cancelled");
throw;
}
finally
{
}
}
Processing Methods:
public void btnStart_Click(object sender, RoutedEventArgs e)
{
LaunchTasks();
}
private void LaunchTasks()
{
Task T;
List<Task> TaskList = new List<Task>();
LogtoStatusText("**** Begin creating tasks *****");
s1.Start();
AProject.FactorClassList.ForEach((f) =>
{
T = new Task(((x) => { OnUIThread(() => { RunningTasks++; }); Factor(f); }), ct);
T.ContinueWith((y) =>
{
if (y.Exception != null)
{
// LogtoStatusText(y.Status + " with "+y.Exception.InnerExceptions[0].GetType()+": "+ y.Exception.InnerExceptions[0].Message);
}
if (!y.IsFaulted)
{
AProject.TotalProcessedAccounts++;
AProject.AverageProcessTime = (((Double)AProject.TotalProcessedAccounts / s1.ElapsedMilliseconds) * 1000);
}
OnUIThread(() => { RunningTasks--; });
OnUIThread(() => { UpdateCounts(AProject); });
});
TaskList.Add(T);
});
try
{
Task.Factory.ContinueWhenAll(TaskList.ToArray(), (z) => { LogtoStatusText("**** Completed all Tasks *****"); OnUIThread(() => { UpdateCounts(AProject); }); });
}
catch (AggregateException a)
{
// For demonstration purposes, show the OCE message.
foreach (var v in a.InnerExceptions)
LogtoStatusText("msg: " + v.Message);
}
LogtoStatusText("**** All tasks have been initialized, begin processing *****");
TaskList.ForEach(t => t.Start());
}
Related
I am trying to splice the work on multiple threads using ThreadPooling. I wanna use every available thread to assign (and calculate in a different part of the program down the line) the output of an array member to another array members.
It does work, but it is much slower than just adding them on a single thread. Is my usage wrong or is this operation too simple for multithreading?
arrayI and arrayX variables are in classScope, i couldnt pass them as QueueUserWorkItem argument without converting them in setNeuronInput.
if (layerType != 0)
{
for (arrayI = 0; arrayI < layerSize -1 ; arrayI++)
{
for (arrayX = 0; arrayX < network.Layers[layerIndex - 1].layerSize - 1; arrayX++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(setNeuronInput), null);
//Neurons[i].input[x] = _network.Layers[layerIndex - 1].Neurons[x].output;
}
}
}
//ThreadPool.GetAvailableThreads(out availableThreads, out placeHolder);
//while (availableThreads != maxThreads)
//{
// ThreadPool.GetAvailableThreads(out availableThreads, out placeHolder);
//}
//return;
}
public void setNeuronInput(object o)
{
try
{
//Console.WriteLine("Thread is working");
Neurons[arrayI].input[arrayX] = network.Layers[layerIndex - 1].Neurons[arrayX].output;
}
catch(Exception e)
{
Console.WriteLine(e);
Console.WriteLine("ArrayI is : " + arrayI);
Console.WriteLine("ArrayX is : " + arrayX);
Console.ReadLine();
}
}
Please help me to understand what went wrong. I have a progress bar method to start running the progress bar in a task. The Base class is the static class which holds the updated values from another class. Below is my code:
private void startProgressBarBA()
{
int tempBA = 0;
proBing.Maximum = Int32.Parse(cboGeoThreshold.Text);
CancellationTokenSource bingBarToken = new CancellationTokenSource();
Task bingTask = Task.Factory.StartNew(() =>
{
while (!bingBarToken.Token.IsCancellationRequested)
{
if (tempBA != Base.proBaValue)//Reduce the number of same value assigned.
{
try
{
Dispatcher.BeginInvoke(new Action(() =>
{
if (proBing.Value == proBing.Maximum)
{
proBing.Value = 0;
Base.proBaValue = 0;
}
proBing.Value = Base.proBaValue;
tempBA = Base.proBaValue;
baRecord.Content = proBing.Value + "/" + proBing.Maximum;
}
));
}
catch(OutOfMemoryException e)
{
throw e;
}
}
if (Base.checkTaskBA == false)
{
bingBarToken.Cancel();
}
}
},bingBarToken.Token, TaskCreationOptions.LongRunning,TaskScheduler.Default);
}
The exception will occurs after a certain time, and the
Dispatcher.BeginInvoke
has been highlighted. Here is the exception message:
System.OutOfMemoryException was unhandled by user code
HResult=-2147024882
Message=Exception of type 'System.OutOfMemoryException' was thrown.
Source=View
StackTrace:
at View.MainWindow.<>c__DisplayClass21_0.<startProgressBarBA>b__0() in C:\Wade\GeocodingApp\Geocoder_v21_Rev_pcode\View\MainWindow.xaml.cs:line 331
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
InnerException:
How to solve this issue? Is it because the
new Action()
causes the OutOfMemoryException? Thanks for everyone's help.
Just a guess here, but it looks like you have no delay in that "while" loop in your task.
That means you are cycling through that loop very quickly, and are creating a huge number of asynchronous "invoke" messages on the Dispatcher queue - no doubt this is eating up all the memory....they aren't being processed fast enough so are building up (i.e. must have 100s thousands/maybe millions of "Action" objects created).
Possible solution....put some kind of "wait" in your while loop e.g. a Thread.Sleep(100) - you don't need to send them out that often to indicate the progress.
private void startProgressBarBA()
{
int tempBA = 0;
proBing.Maximum = Int32.Parse(cboGeoThreshold.Text);
CancellationTokenSource bingBarToken = new CancellationTokenSource();
Task bingTask = Task.Factory.StartNew(() =>
{
while (!bingBarToken.Token.IsCancellationRequested)
{
if (tempBA != Base.proBaValue)//Reduce the number of same value assigned.
{
try
{
Dispatcher.BeginInvoke(new Action(() =>
{
if (proBing.Value == proBing.Maximum)
{
proBing.Value = 0;
Base.proBaValue = 0;
}
proBing.Value = Base.proBaValue;
tempBA = Base.proBaValue;
baRecord.Content = proBing.Value + "/" + proBing.Maximum;
}
));
}
catch(OutOfMemoryException e)
{
throw e;
}
}
if (Base.checkTaskBA == false)
{
bingBarToken.Cancel();
}
Thread.Sleep(100);
}
},bingBarToken.Token, TaskCreationOptions.LongRunning,TaskScheduler.Default);
}
public IDisposable subscription;
public ProcessData(DeviceModel model, string name = "") : base(model, name)
{
BaseAddress = _model.Process.oxyVal.regAddr;
CurrentSampleRate=1000;
subscription = Observable.Interval(TimeSpan.FromMilliseconds(CurrentSampleRate)).Subscribe(async t => await Refresh());
}
public async Task Refresh()
{
Status = "Fetching from device...";
if ((_model == null) || !_model.IsSerialPortOpen || busy)
{
StatusTrans = "Device not connected.";
return;
}
busy = true;
try
{
await ReadFromDevice().ConfigureAwait(false);
StatusTrans = "Completed.";
}
catch (Exception ex)
{
StatusTrans = ex.Message;
Trace.WriteLine(ex.Message);
}
busy = false;
}
protected override async Task ReadFromDevice()
{
var SampleRate_var = await _model.Measurement.sampleRate.sampleRate.GetValue();
CurrentSampleRate = SampleRate_var * 1000;
/*****other code********/
}
public void ChangeSampleRate()
{
subscription?.Dispose();
Observable.Interval(TimeSpan.FromMilliseconds(CurrentSampleRate)).Subscribe(async t => await Refresh());
}
I have been trying to fetching details from device.On the start,i'll subscribe a event 1 sec,in the it try to read from device(ReadFromDevice) and i'll change get the CurrentSampleRate,Onproperty change,that time I'll dispose 1sec subscribe event and i will subscribe new event with current sample rate.But problem is ReadFromDevice happens at every 1 sec.
Try this:
var CurrentSampleRate = 30;
Observable
.Generate(0, x => true, x => x + 1, x => x, x => TimeSpan.FromMilliseconds(CurrentSampleRate))
.Subscribe(x =>
{
if (x == 50)
{
CurrentSampleRate = 1000;
}
Console.Write(".");
});
It's a little nasty in that you're changing some external state to make the observable's interval change - so you may need to use Interlocked.Exchange to make the update safe.
I am using this method to open specific work with concurrent Threads from my Main UI thread:
private List<MyData> MyCollection;
private static CancellationTokenSource _tokenSource;
private void Start()
{
int concurrentThread = (int)nudConcurrentFiles.Value;
int loops = (int)nudLoops.Value;
var token = _tokenSource.Token;
Task.Factory.StartNew(() =>
{
try
{
while (Iteration.LoopFinished < loops)
{
Parallel.ForEach(PcapList.Files,
new ParallelOptions
{
MaxDegreeOfParallelism = concurrentThread //limit number of parallel threads
},
File=>
{
if (token.IsCancellationRequested)
return;
//do work...
});
Iteration.LoopFinished++;
Task.Delay(10000).ContinueWith(
t =>
{
}, _tokenSource.Token);
}
}
catch (Exception e)
{ }
}, _tokenSource.Token,
TaskCreationOptions.None,
TaskScheduler.Default).ContinueWith(
t =>
{
}
);
}
The problem is that after loop i want to wait 10 secons and Task.Delay(10000).ContinueWith not waiting this 10 seconds but start immedietly another loop.
You need to call Wait() method in order to execute the task
Task.Delay(10000).ContinueWith(
t =>
{
}, _tokenSource.Token).Wait();
I have one problem. In my project i need for more then 100 threads, that's why i prefer to use ThreadPool. here is a part of code, but in this case i have got a lot of memory usage and my form is very laggy, cuz of A lot of BeginInvoke calls(i suppose).
Is there any solutions for this problem?
public void launch()
{
while (data.Count > 0)
{
string[] part;
if (data.Count> 1000)
{
part = data.Take(1000).ToArray();
data = data.Skip(1000).ToList();
}
else
{
part = data.Take(data.Count).ToArray(); data = data.Skip(1000).ToList();
}
foreach (var input in part)
{
try
{
char splitter = ':';
if (input.Contains(';')) splitter = ';';
string login = input.Split(splitter)[0];
string pass = input.Split(splitter)[1];
EncryptCore ec = new EncryptCore(new byte[15]);
PacketSend ps = new PacketSend(ec, "");
ps._login = login;
ps._password = pass;
ps.Brutted+=ps_Parsed;
ps.Failed+=ps_Failed;
ThreadPool.QueueUserWorkItem(ps.Parse);
}
catch { Interlocked.Increment(ref curr); }
}
Thread.Sleep(1000);
}
data.Clear();
}
private void ps_Brutted(User Account)
{
toGet.Add(Account);
Interlocked.Increment(ref good);
goodLabl.BeginInvoke(new Action(delegate()
{
goodLabl.Text = "Good: " + good;
}));
Update();
}
private void Update()
{
try
{
Interlocked.Increment(ref curr);
progLabel.BeginInvoke(new Action(delegate()
{
progLabel.Text = (double.Parse(curr.ToString()) / double.Parse(max.ToString())).ToString("#%");
}));
progressBar.BeginInvoke(new Action(delegate()
{
progressBar.Text = (double.Parse(curr.ToString()) / double.Parse(max.ToString()) * 100).ToString("#");
}));
checkedLabl.BeginInvoke(new Action(delegate()
{
checkedLabl.Text = "Checked: " + curr + " / " + max;
}));
}
catch { }
}
So you have thousands of tasks, and each time one of them completes you update the UI by scheduling 4 updates on the UI thread. What you might consider doing is having the UI update on a timer-based schedule (try 100ms or 200ms) based on the integers that are updating.
Aside from that, you've got some strange numeric operations going on. You can just cast an int to a double, you don't have to round-trip through a String.