Problem
In a project case I need to create multiple threads that are picking tasks from a queue and running them. Some of these tasks cannot run if a group of other tasks are still running. Consider something like file copy and defrag (runs when system is idle) in windows .
Solution
To implement this, I created a class based on
System.Threading.CountdownEvent.
Whenever a thread picks a blocking task from queue, they will Increment the CounterEvent and after they finished their job they will Decrement the CounterEvent.
If a thread picks a low priority task, it will Wait until CounterEvent is zero then starts running.
A low priority taks can immediately start with Reset of CounterEvent
Main thread or a parallel thread can monitor the status of lock by querying the CurrentCount.
Here is the Code:
using System;
using System.Diagnostics.Contracts;
using System.Threading;
public class CounterEvent : IDisposable {
private volatile int m_currentCount;
private volatile bool m_disposed;
private ManualResetEventSlim m_event;
// Gets the number of remaining signals required to set the event.
public int CurrentCount {
get {
return m_currentCount;
}
}
// Allocate a thin event, Create a latch in signaled state.
public CounterEvent() {
m_currentCount = 0;
m_event = new ManualResetEventSlim();
m_event.Set(); //
}
// Decrements the counter. if counter is zero signals other threads to continue
public void Decrement() {
ThrowIfDisposed();
Contract.Assert(m_event != null);
int newCount = 0;
if (m_currentCount >= 0) {
#pragma warning disable 0420
newCount = Interlocked.Decrement(ref m_currentCount);
#pragma warning restore 0420
}
if (newCount == 0) {
m_event.Set();
}
}
// increments the current count by one.
public void Increment() {
ThrowIfDisposed();
#pragma warning disable 0420
Interlocked.Increment(ref m_currentCount);
#pragma warning restore 0420
}
// Resets the CurrentCount to the value of InitialCount.
public void Reset() {
ThrowIfDisposed();
m_currentCount = 0;
m_event.Set();
}
// Blocks the current thread until the System.Threading.CounterEvent is set.
public void Wait() {
ThrowIfDisposed();
m_event.Wait();
}
/// <summary>
/// Throws an exception if the latch has been disposed.
/// </summary>
private void ThrowIfDisposed() {
if (m_disposed) {
throw new ObjectDisposedException("CounterEvent");
}
}
// According to MSDN this is not thread safe
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
// According to MSDN Dispose() is not thread-safe.
protected virtual void Dispose(bool disposing) {
if (disposing) {
m_event.Dispose();
m_disposed = true;
}
}
}
Question
will this code work as expected?
Any flaws that I didn't see in it?
Is there any better option doing this?
Note
Application is written with System.Threading.Thread and cost of converting it for me is very high, however a great replacement solution always worth working on for future.
This should be one atomic operation and it is not threadsafe if you do it like this
if (m_currentCount >= 0)
{
newCount = Interlocked.Decrement(ref m_currentCount);
}
It may happen that m_currentCount is changed between the if and the Interlocked.Decrement
You should rewrite your logic to use Interlocked.CompareExchange I would also use Interlocked.Exchange in every place where you assign to m_currentCount then you don´t need volatile and the pragma You should also be aware of that under very heavy load it can happen that a reset event Set is getting lost
Related
I am trying to handle exceptions from a System.Threading.Tasks.Task
I haven't used these before, and seem to be misunderstanding how the ContinueWith works; thus my ContinueWith is firing at the wrong time.
Given the following; workers is just a list of my long running processes.
......
workers.Add(new Workers.Tests.TestWorker1());
workers.Add(new Workers.Tests.TestWorker2());
// Start all the workers.
workers.ForEach(worker =>
{
// worker.Start schedules a timer and calls DoWork in the worker
System.Threading.Tasks.Task task = new System.Threading.Tasks.Task(worker.Start);
task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
task.Start();
})
.....
My handler method is
private void ExceptionHandler(System.Threading.Tasks.Task arg1, object arg2)
{
DebugLogger.Write("uh oh.. it died");
}
My TestWorker's are:
class TestWorker1 : Worker
{
int count = 1;
public override void DoWork(object timerState)
{
DebugLogger.Write(string.Format("{0} ran {1} times", workerName, count));
count++;
ScheduleTimer();
}
}
And
class TestWorker2 : Worker
{
int count = 1;
public override void DoWork(object timerState)
{
DebugLogger.Write(string.Format("{0} ran {1} times", workerName, count));
count++;
if (count == 3)
throw new Exception("I'm going to die....");
ScheduleTimer();
}
}
ScheduleTimer() simply sets an interval for DoWork to be run
What happens...
When I debug, all tasks are created and started. As soon as theDoWork has called ScheduleTimer() for the first time, my ExceptionHandler is hit; as shown in this screenshot - this happens for both workers.
When the exception is hit in TestWorker2 the debugger will not move on from there - in that i press continue, hoping to hit my ExceptionHandler, and the debugger just keeps throwing the exception.
What I am hoping to achieve
I would like my ExceptionHandler to only fire when an exception within the running tasks is thrown. I'm finding the only time i get into my ExceptionHandler is when it's run, and my actual exception just keeps looping.
What am i missing?
Per comment, here is the code for the main Worker
public abstract class Worker : IDisposable
{
internal string workerName;
internal Timer scheduler;
internal DateTime scheduledTime;
public Worker()
{
string t = this.GetType().ToString();
workerName = t.Substring(t.LastIndexOf(".") + 1).AddSpacesBeforeUppercase(true).Trim();
}
/// <summary>
/// Set to true when the worker is performing its task, false when its complete
/// </summary>
public bool IsCurrentlyProcessing { get; set; }
public void Start()
{
DebugLogger.Write(workerName + " Started");
ScheduleTimer();
}
/// <summary>
/// default functionality for setting up the timer.
/// Typically, the timer will fire in 60 second intervals
/// Override this method in child classes for different functionality
/// </summary>
public virtual void ScheduleTimer()
{
scheduler = new Timer(new TimerCallback(DoWork));
int interval = 60;
int.TryParse(ConfigurationManager.AppSettings[string.Format("{0}{1}", workerName.Replace(" ", ""), "Interval")], out interval);
scheduledTime = DateTime.Now.AddSeconds(interval);
if (DateTime.Now > scheduledTime)
scheduledTime = scheduledTime.AddSeconds(interval);
int dueTime = Convert.ToInt32(scheduledTime.Subtract(DateTime.Now).TotalMilliseconds);
scheduler.Change(dueTime, Timeout.Infinite);
}
public abstract void DoWork(object timerState);
public void Stop()
{
// kill stuff
if (scheduler != null)
scheduler.Dispose();
DebugLogger.Write(workerName + " stop");
this.Dispose();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
if (disposing)
{
// any specific cleanup
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
From your screenshot it appears that arg2 is your TaskContinuationOptions.OnlyOnFaulted object, that is the biggest clue of what is going wrong. Because you passed in a Action<Task, Object> it is using the Task.ContinueWith Method (Action<Task, Object>, Object) overload of ContinueWith, this is causing your continuation options to be passed in as the state parameter.
Either change ExceptionHandler to
private void ExceptionHandler(System.Threading.Tasks.Task arg1)
{
DebugLogger.Write("uh oh.. it died");
}
so you will use the Task.ContinueWith(Action<Task>, TaskContinuationOptions) overload, or you can change your call to
task.ContinueWith(ExceptionHandler, null, TaskContinuationOptions.OnlyOnFaulted);
so that you will start using the Task.ContinueWith(Action<Task, Object>, Object, TaskContinuationOptions) overload.
Might be caused by your logging component not supporting multiple concurrent writes.
If it's possible for you, I'd suggest you refactor the code to the async/await pattern, it will be much more readable.
Let's say you create a list of all the tasks you want to run:
List<Task> tasks = new List<Task>();
workers.ForEach(worker => tasks.Add(Task.Run(() => worker.Start())));
and then use await on the list surrounded by a try catch block:
try
{
await Task.WhenAll(tasks);
}
catch (Exception ex)
{
DebugLogger.Write("uh oh.. it died");
}
Also, make sure you are not doing any Thread.Wait(xxx) calls (or any other Thread.XXX calls for that matter) inside ScheduleTimer(), because tasks and threads don't play nice together.
Hope it helps!
This block of code is being accessed by many threads
// All code is from same class
public void ExecuteCommand(IAsciiCommand command, IAsciiCommandSynchronousResponder responder)
{
lock (commander)
{
if (commander.IsConnected)
{
commander.ExecuteCommand(command, responder);
}
}
}
public void Disconnect()
{
var tmp = commander.IsConnected;
commander.Disconnect();
if (commander.IsConnected != tmp && !commander.IsConnected)
{
OnPropertyChanged("IsConnected");
}
}
And eventually i get this:
How is this possible, that thread accessed into if statement, whose condition returns false? How can i fix it?
This is happening because the check and the call lack atomicity. Here is a sequence of events that could lead to an exception:
Two threads, A and B, are reaching the condition at the same time
Thread A checks the condition, which returns true, so it enters the if block
At the same time, thread scheduler decides that thread A has exhausted its time slot, and suspends it
Thread B calls Disconnect
Thread scheduler resumes thread A, which is inside the if condition. However, the command is no longer connected
This causes the exception
You can fix it by locking commander inside Disconnect().
public void Disconnect()
{
bool doEvent;
lock(commander) {
var tmp = commander.IsConnected;
commander.Disconnect();
doEvent = (commander.IsConnected != tmp && !commander.IsConnected)
}
// Run OnPropertyChanged outside the locked context
if (doEvent)
{
OnPropertyChanged("IsConnected");
}
}
You need to lock on a static object. Right now you're creating separate locks based on the object your are working with (commander). Try this:
public class WhatEverClassHasTheExecuteCommandMethod
{
private static object _lock = new object();
public void ExecuteCommand(IAsciiCommand command, IAsciiCommandSynchronousResponder responder)
{
lock (_lock)
if (commander.IsConnected)
commander.ExecuteCommand(command, responder);
}
}
If you are not locking while disconnecting, it's entirely possible to get a race condition. The basic solution is to add a lock inside the Disconnect method:
public void Disconnect()
{
lock (commander)
{
var tmp = commander.IsConnected;
commander.Disconnect();
if (commander.IsConnected != tmp && !commander.IsConnected)
OnPropertyChanged("IsConnected");
}
}
I receive this error in a windows service.
This is the same service that I've previously discussed in my question here
The code is revised to use Parallel.ForEach (my own version as this is a 3.5 windows service). The reason for the Parallel use is down to the fact that it simply took too long to Unload each domain and running them in parallel should prove to be faster (appears to be even though there is only one thread that's doing each Unload?!).
Based on other posts, I can only guess that this is somehow down to the fact I am using a ThreadPool Thread to Unload the AppDomains. I just can't see how to avoid it?
public partial class SomeService : ServiceBase
{
private Manager _appDomainManager;
protected override void OnStop()
{
_appDomainManager.Dispose();
}
}
public class Manager : IDisposable
{
public void Dispose()
{
Log.Debug("Disposing");
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
// dispose managed resources
Parallel.For(0, appdomains.Length, UnloadAppDomian);
}
_disposed = true;
}
}
private UnloadAppDomain(int appDomainIndex);
public static class Parallel35
{
public static void For(int start, int end, Action<int> action)
{
var waitHandles = new WaitHandle[end - start];
for (int j = 0; j < waitHandles.Length; j++)
{
waitHandles[j] = new ManualResetEvent(false);
}
for (int i = start; i < end; i++)
{
int i1 = i - start;
ThreadPool.QueueUserWorkItem(
state =>
{
try
{
action((int) state);
}
finally
{
((ManualResetEvent) waitHandles[i1]).Set();
}
}, i);
}
WaitHandle.WaitAll(waitHandles);
}
}
I tracked down this as a bug to one of the AppDomains on exit waiting for a WaitHandle that's never set.
If a thread does not abort, for example because it is executing
unmanaged code, or because it is executing a finally block, then after
a period of time a CannotUnloadAppDomainException is thrown in the
thread that originally called Unload.
The AppDomain now unloads relatively quickly and my service stops quite quickly.
Try to unload all AppDomains in a single background task instead of one background task for each AppDomain and use ServiceBase.RequestAdditionalTime so that the SCM does not mark your service as not responsive.
Consider this example:
When the user clicks a button, ClassA fires OnUserInteraction event rapidly 10 times. ClassB is attached to this event and in it's event handler it fires ClassC's Render method. In the Render method the AxisAngleRotation3D is executed, but every single animation is lasting 1 second.
In this scenario all 10 AxisAngleRotation3D animations are executed almost at the same time, but I would want them to execute one after another. As I understand threads, I would probably have to implement a thread queue in ClassB, where the Completed event of the AxisAngleRotation3D signals that the next event is allowed to fire...?
Is this correct and how can I achieve this?
Have a task queue. Simply put, have a ConcurrentQueue<Func<bool>> field or similar, and add tasks to it as necessary. Then have your task execution thread pop Func<bool> delegates off the queue and invoke them. If they return true, they're done. If they return false, add them back onto the queue, as they couldn't complete at that time.
Here's an example:
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace Example
{
public class TaskScheduler : IDisposable
{
public const int IDLE_DELAY = 100;
private ConcurrentQueue<Func<bool>> PendingTasks;
private Thread ExecuterThread;
private volatile bool _IsDisposed;
public bool IsDisposed
{
get { return _IsDisposed; }
}
public void EnqueueTask(Func<bool> task)
{
PendingTasks.Enqueue(task);
}
public void Start()
{
CheckDisposed();
if (ExecuterThread != null)
{
throw new InvalidOperationException("The task scheduler is alreader running.");
}
ExecuterThread = new Thread(Run);
ExecuterThread.IsBackground = true;
ExecuterThread.Start();
}
private void CheckDisposed()
{
if (_IsDisposed)
{
throw new ObjectDisposedException("TaskScheduler");
}
}
private void Run()
{
while (!_IsDisposed)
{
if (PendingTasks.IsEmpty)
{
Thread.Sleep(IDLE_DELAY);
continue;
}
Func<bool> task;
while (!PendingTasks.TryDequeue(out task))
{
Thread.Sleep(0);
}
if (!task.Invoke())
{
PendingTasks.Enqueue(task);
}
}
}
public void Dispose()
{
CheckDisposed();
_IsDisposed = true;
}
}
}
ClassB could add the event to a queue and then render them one at a time (possibly use a timer to read from the queue).
I have a job object made up of a collection of work items. Each job has it's own WatcherClass associated with it that checks the database every so often to see if it needs to cancel execution. It could be cancelled at any iteration in the workflow. IF it is cancelled, any threads running from the foreach block will propagate the cancellation and exit gracefully.
Is there any problem in my watcher code that could create a deadlock? I am trying to only allow one thread to process on the timer callback by using Timer.Change(Timeout.Infinite, Timeout.Infinite), but does the fact that I am changing WatcherClass.Job inside the lock statement defeat the lock's purpose (since I wrapped the same get/set for _Job in the same lock object)? The code appears to be working fine, but I know that is no indication of anything really.
The code in the main thread looks similiar to this:
using (WatcherClass watcher = new WatcherClass())
{
watcher.CancelTokenSource = new CancellationTokenSource();
watcher.Start();
foreach (SomeJob job in worksflow.Jobs)
{
watcher.Job = job;
//Do some stuff async
//Do some more stuff async
}
}
public class WatcherClass : IDisposable
{
private System.Threading.Timer _WatcherTimer;
private readonly object locker = new object();
private bool _Disposed = false;
private SomeJob _Job;
public SomeJob Job
{
get
{
lock (locker)
{
return _Job;
}
}
set
{
lock (locker)
{
_Job= value;
}
}
}
public System.Threading.Task.CancellationTokenSource
CancelToken { get; set; }
public WatcherClass()
{
_WatcherTimer = new Timer(new TimerCallback(DoCheck), null,
Timeout.Infinite, Timeout.Infinite);
}
public void Start()
{
_WatcherTimer.Change(30000, Timeout.Infinite);
}
public void DoCheck(object state)
{
lock (locker)
{
if (_Disposed || this.CancelToken.IsCancellationRequested)
return;
_WatcherTimer.Change(Timeout.Infinite, Timeout.Infinite);
//Check database to see if task is cancelled
if (cancelled)
{
this.CancelToken.Cancel();
_Job.CancelResult = CancelResult.CanceledByUser;
_Job.SomeOtherProperty = true;
}
else
{
//Safe to continue
_WatcherTimer.Change(30000, Timeout.Infinite);
}
}
}
public void Dispose(bool disposing)
{
lock (locker)
{
if (disposing)
{
if (_WatcherTimer != null)
_WatcherTimer.Dispose();
}
_Disposed = true;
}
}
}
The lock you aquire around the Task property and in the DoCheck function only protects access to the internal _task field of the WatcherClass. In DoCheck, you are also modifying properties of the _task object itself. The lock does not prevent anyone else from also modifying the task object's fields at the same time from other threads.
If in your application the task object is only manipulated by DoCheck, then you're probably ok. If the task object may be manipulated by code other than DoCheck, then you may have a problem.
Also keep in mind that every additional lock you create is an additional opportunity for deadlock. Multiple locks can be deadlock-free if they are always acquired in a specific order. If the code flow allows for lock A to be acquired before lock B in some situations, or lock B before lock A in other situations, then you have a serious deadlock risk. (Thread 1 locks A, tries to lock B while thread 2 locks B and tries to lock A => deadlock)
In your WatcherClass case, if you are going to have multiple watcherclass instances each with their own locks, be careful not to make external calls (or fire events) that could end up trying to acquire locks in other watcherclass instances. That's an AB / BA deadlock waiting to happen.