Can someone explain whether or not I can call the below class "thread safe"?
As far as I know, we can call something thread safe if we are not breaking existing functionality
Example:
public class BackgroundWorker
{
private readonly IDictionary<string, RunningTask> _runningTasks = new ConcurrentDictionary<string, RunningTask>();
/// <summary>
/// Executes async job for the specified key, only one at a time.
/// </summary>
/// <param name="key"></param>
public void Enqueue(string key)
{
if (_runningTasks.ContainsKey(key))
{
_runningTasks[key].Repeat = true;
return;
}
_runningTasks[key] = new RunningTask();
ExecuteTask(key);
}
private void ExecuteTask(string key)
{
Task.Run(() =>
{
// Do something
if (_runningTasks[key].Repeat)
{
_runningTasks[key].Repeat = false;
ExecuteTask(key);
return;
}
_runningTasks.Remove(key);
});
}
private class RunningTask
{
/// <summary>
/// Flag to repeat a task after completion.
/// </summary>
public bool Repeat { get; set; }
}
}
I don't think so because _runningTasks is shared object and your method Enqueue is writing on this shared object. For example its possible when one thread already executed line number y, another thread will evaluate condition check in line number x as true - which might not be intention.
public void Enqueue(string key)
{
if (_runningTasks.ContainsKey(key)) /*say line no : x */
{
_runningTasks[key].Repeat = true;
return;
}
_runningTasks[key] = new RunningTask(); /*say line no:y*/
ExecuteTask(key);
}
Using ConcurrentDictionary will just ensure no two threads can read/write to/from the dictionary same time.
To your second point :
As far as I know, we can call something thread safe if we are not
breaking existing functionality
No this is not the definition of thread safe (might be ok to say one of desirable outcome in multi threaded environment) I would recommend to read this post for official meaning rather.
Related
I have multiple producers and multiple consumers. My shared resource is the BlockingCollection. However, my code only works if I have one consumer. I know it is a race condition since the output is different each time I run the code.
I thought BlockingCollection would take care of all the syncing etc. but it does not.
How can I sync my shared resource among all the producers and consumers then?
Here is my code:
/// <summary>
/// PURE PRODUCER TYPE
/// </summary>
class Caller
{
private BlockingCollection<Call> incommingCalls;
public Caller(BlockingCollection<Call> calls)
{
incommingCalls = calls;
//start the producer thread
Thread thread = new Thread(new ThreadStart(placeCall));
thread.Start();
}
public void placeCall()
{
incommingCalls.Add(myCall);
}
}
/// <summary>
/// CONSUMER
/// </summary>
class Fresher : Employee
{
private BlockingCollection<Call> calls;
public Fresher(BlockingCollection<Call> incalls)
{
calls = incalls;
Thread thread = new Thread(new ThreadStart(HandleCalls));
thread.Start();
}
/// <summary>
///
/// </summary>
public void HandleCalls()
{
while (!incommingCalls.IsCompleted)
{
Call item;
if (incommingCalls.TryTake(out item, 100000))
{
//do something with the call
} //else do nothing - just wait
}
}
/// <summary>
///
/// </summary>
class CallCenter
{
private BlockingCollection<Call> fresherCalls;
private List<Caller> myCallers;
private List<Employee> myFreshers;
public CallCenter()
{
//initial incomming calls to the fresher queue
fresherCalls = new BlockingCollection<Call>();
myFreshers = new List<Employee>();
myCallers = new List<Caller>();
generate_freshers();
//generate to start the producer
generate_callers();
}
/// <summary>
///
/// </summary>
private void generate_freshers()
{
for (int i = 0; i < 1; i++ )
{
myFreshers.Add(new Fresher(fresherCalls, tlCalls, locker2));
}
}
/// <summary>
///
/// </summary>
private void generate_callers()
{
for (int i = 0; i < 20; i++ )
{
myCallers.Add(new Caller(fresherCalls, locker));
}
}
}
I know it is a race condition since the output is different each time I run the code.
This is common with multithreading, and not necessarily due to a race condition (at least not a bad one). Order processing in multithreaded scenarios tends to not be deterministic - which would likely change the output.
That being said, with BlockingCollection<T>, it's typically easier to write your consumers as:
public void HandleCalls()
{
foreach(var item in incommingCalls.GetConsumingEnumerable())
{
//do something with the call
}
}
This will handle all of the synchronization and checking for you, for any number of consumers on the BlockingCollection<T>.
Edit: If you need to control the scheduling, and implement some form of Round-Robin Scheduling, you may want to take a look at the Parallel Extension Extras within the samples for the TPL. They provide a RoundRobinTaskScheduler which can be used to schedule Task<T> instances which work in a predictable manner.
I've written class, which is an enumerable wrapper that caches the results of an underlying enumerable, only getting the next element if we enumerate and reach the end of the cached results. It can be multi-threaded (getting the next item in another thread) or single threaded (getting the next item in the current thread).
I'm reading up on unit-testing and would like to get my head around appropriate tests. I'm using nunit. My main issue is that i've already written my class and am using it. It works for what i'm using it for (one thing currently). So, i'm writing my tests by just trying to think of things that could go wrong, which given that i've tested unofficially i'm probably unconsciously writing tests i know i've already checked. How can i get the write balance between too many/fine-grained tests, and too few tests?
Should i only be testing public methods/constructors or should i test every method?
Should i test the CachedStreamingEnumerable.CachedStreamingEnumerator class separately?
Currently i'm only testing when the class is set to be single-threaded. How do i go about testing it when multi-threaded, given that i might need to wait a period of time before an item is retrieved and added to the cache?
What tests am i missing to ensure good coverage? Are any i've already got not needed?
Code for the class, and test class below.
CachedStreamingEnumerable
/// <summary>
/// An enumerable that wraps another enumerable where getting the next item is a costly operation.
/// It keeps a cache of items, getting the next item from the underlying enumerable only if we iterate to the end of the cache.
/// </summary>
/// <typeparam name="T">The type that we're enumerating over.</typeparam>
public class CachedStreamingEnumerable<T> : IEnumerable<T>
{
/// <summary>
/// An enumerator that wraps another enumerator,
/// keeping track of whether we got to the end before disposing.
/// </summary>
public class CachedStreamingEnumerator : IEnumerator<T>
{
public class DisposedEventArgs : EventArgs
{
public bool CompletedEnumeration;
public DisposedEventArgs(bool completedEnumeration)
{
CompletedEnumeration = completedEnumeration;
}
}
private IEnumerator<T> _UnderlyingEnumerator;
private bool _FinishedEnumerating = false;
// An event for when this enumerator is disposed.
public event EventHandler<DisposedEventArgs> Disposed;
public CachedStreamingEnumerator(IEnumerator<T> UnderlyingEnumerator)
{
_UnderlyingEnumerator = UnderlyingEnumerator;
}
public T Current
{
get { return _UnderlyingEnumerator.Current; }
}
public void Dispose()
{
_UnderlyingEnumerator.Dispose();
if (Disposed != null)
Disposed(this, new DisposedEventArgs(_FinishedEnumerating));
}
object System.Collections.IEnumerator.Current
{
get { return _UnderlyingEnumerator.Current; }
}
public bool MoveNext()
{
bool MoveNextResult = _UnderlyingEnumerator.MoveNext();
if (!MoveNextResult)
{
_FinishedEnumerating = true;
}
return MoveNextResult;
}
public void Reset()
{
_FinishedEnumerating = false;
_UnderlyingEnumerator.Reset();
}
}
private bool _MultiThreaded = false;
// The slow enumerator.
private IEnumerator<T> _SourceEnumerator;
// Whether we're currently already getting the next item.
private bool _GettingNextItem = false;
// Whether we've got to the end of the source enumerator.
private bool _EndOfSourceEnumerator = false;
// The list of values we've got so far.
private List<T> _CachedValues = new List<T>();
// An object to lock against, to protect the cached value list.
private object _CachedValuesLock = new object();
// A reset event to indicate whether the cached list is safe, or whether we're currently enumerating over it.
private ManualResetEvent _CachedValuesSafe = new ManualResetEvent(true);
private int _EnumerationCount = 0;
/// <summary>
/// Creates a new instance of CachedStreamingEnumerable.
/// </summary>
/// <param name="Source">The enumerable to wrap.</param>
/// <param name="MultiThreaded">True to load items in another thread, otherwise false.</param>
public CachedStreamingEnumerable(IEnumerable<T> Source, bool MultiThreaded)
{
this._MultiThreaded = MultiThreaded;
if (Source == null)
{
throw new ArgumentNullException("Source");
}
_SourceEnumerator = Source.GetEnumerator();
}
/// <summary>
/// Handler for when the enumerator is disposed.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Enum_Disposed(object sender, CachedStreamingEnumerator.DisposedEventArgs e)
{
// The cached list is now safe (because we've finished enumerating).
lock (_CachedValuesLock)
{
// Reduce our count of (possible) nested enumerations
_EnumerationCount--;
// Pulse the monitor since this could be the last enumeration
Monitor.Pulse(_CachedValuesLock);
}
// If we've got to the end of the enumeration,
// and our underlying enumeration has more elements,
// and we're not getting the next item already
if (e.CompletedEnumeration && !_EndOfSourceEnumerator && !_GettingNextItem)
{
_GettingNextItem = true;
if (_MultiThreaded)
{
ThreadPool.QueueUserWorkItem((Arg) =>
{
AddNextItem();
});
}
else
AddNextItem();
}
}
/// <summary>
/// Adds the next item from the source enumerator to our list of cached values.
/// </summary>
private void AddNextItem()
{
if (_SourceEnumerator.MoveNext())
{
lock (_CachedValuesLock)
{
while (_EnumerationCount != 0)
{
Monitor.Wait(_CachedValuesLock);
}
_CachedValues.Add(_SourceEnumerator.Current);
}
}
else
{
_EndOfSourceEnumerator = true;
}
_GettingNextItem = false;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
lock (_CachedValuesLock)
{
var Enum = new CachedStreamingEnumerator(_CachedValues.GetEnumerator());
Enum.Disposed += new EventHandler<CachedStreamingEnumerator.DisposedEventArgs>(Enum_Disposed);
_EnumerationCount++;
return Enum;
}
}
}
CachedStreamingEnumerableTests
[TestFixture]
public class CachedStreamingEnumerableTests
{
public bool EnumerationsAreSame<T>(IEnumerable<T> first, IEnumerable<T> second)
{
if (first.Count() != second.Count())
return false;
return !first.Zip(second, (f, s) => !s.Equals(f)).Any(diff => diff);
}
[Test]
public void InstanciatingWithNullParameterThrowsException()
{
Assert.Throws<ArgumentNullException>(() => new CachedStreamingEnumerable<int>(null, false));
}
[Test]
public void SameSequenceAsUnderlyingEnumerationOnceCached()
{
var SourceEnumerable = Enumerable.Range(0, 10);
var CachedEnumerable = new CachedStreamingEnumerable<int>(SourceEnumerable, false);
// Enumerate the cached enumerable completely once for each item, so we ensure we cache all items
foreach (var x in SourceEnumerable)
{
foreach (var i in CachedEnumerable)
{
}
}
Assert.IsTrue(EnumerationsAreSame(Enumerable.Range(0, 10), CachedEnumerable));
}
[Test]
public void CanNestEnumerations()
{
var SourceEnumerable = Enumerable.Range(0, 10).Select(i => (decimal)i);
var CachedEnumerable = new CachedStreamingEnumerable<decimal>(SourceEnumerable, false);
Assert.DoesNotThrow(() =>
{
foreach (var d in CachedEnumerable)
{
foreach (var d2 in CachedEnumerable)
{
}
}
});
}
}
Ad 1)
If you need to test private methods, this should tell you something; probably that your class has too much responsibilities. Quite often, private methods are separate classes waiting to be born :-)
Ad 2)
Yes
Ad 3)
Following the same argument as 1, threading functionality should probably not be done inside the class if it can be avoided. I recall reading something about this in "Clean Code" by Robert Martin. He states something like that threading is a separate concern, that should be separated from other peaces of business logic.
Ad 4)
The private methods are the hardest to cover. Thus, I again turn to my answer 1. If your private methods were public methods in seperate classes, they would be much easier to cover. Also, the test of your main class would be easier to understand.
Regards,
Morten
Rather than riddle you with details, I'd simply advise you to be practical and to follow the "Law of the Critical Few" when creating your tests. You do not need to test every accessor or every small fragment of industry-standard code.
Think of what kinds of things would hurt your class the worst and guard against them. Check for boundary conditions. Use any memories you have as to what may have broken similar code in your past experience. Try test data values that may be unexpected.
You are probably not doing this as an academic exercise. You probably want to ensure that your class is solid and that it will stay that way when you go back later to refactor it or when you want to ensure that it is not the cause of misbehavior in one of its client classes.
Your every test should be there for a reason, not just so you can be cool at the next TDD club meeting!
I want to create a windows service that will create x number of threads that wake up every x number of minutes and do some work.
I think the task scheduling or parallel framework is a bad fit for this type of work as it is best suited for work that starts, completes and finishes rather than is constant.
Should I look at utilising a thread pool for this approach or does anyone have any advice for a good solution?
Really, it sounds like you only need one thread.
Here's a helper class that I created for exactly this kind of thing. Here's how you use it:
class MyPeriodicTasks : PeriodicMultiple
{
// The first task will start 30 seconds after this class is instantiated and started:
protected override TimeSpan FirstInterval { get { return TimeSpan.FromSeconds(30); } }
public MyPeriodicTasks()
{
Tasks = new[] {
new Task { Action = task1, MinInterval = TimeSpan.FromMinutes(5) },
new Task { Action = task2, MinInterval = TimeSpan.FromMinutes(15) },
};
}
private void task1() { /* code that gets executed once every 5 minutes */ }
private void task2() { /* code that gets executed once every 15 minutes */ }
}
Then, to start the tasks:
var tasks = new MyPeriodicTasks();
tasks.Start();
And during service shutdown:
tasks.Shutdown();
(alternatively, call Start with backgroundThread: true, then you don't need to call Shutdown, but then a task may just get terminated right in the middle of doing something)
Here's the actual code:
/// <summary>
/// Encapsulates a class performing a certain activity periodically, which can be initiated once
/// and then permanently shut down, but not paused/resumed. The class owns its own separate
/// thread, and manages this thread all by itself. The periodic task is executed on this thread.
/// <para>The chief differences to <see cref="System.Threading.Timer"/> are as follows. This
/// class will never issue overlapping activities, even if an activity takes much longer than the interval;
/// the interval is between the end of the previous occurrence of the activity and the start of the next.
/// The activity is executed on a foreground thread (by default), and thus will complete once started,
/// unless a catastrophic abort occurs. When shutting down the activity, it's possible to wait until the
/// last occurrence, if any, has completed fully.</para>
/// </summary>
public abstract class Periodic
{
private Thread _thread;
private CancellationTokenSource _cancellation;
private ManualResetEvent _exited;
/// <summary>
/// Override to indicate how long to wait between the call to <see cref="Start"/> and the first occurrence
/// of the periodic activity.
/// </summary>
protected abstract TimeSpan FirstInterval { get; }
/// <summary>
/// Override to indicate how long to wait between second and subsequent occurrences of the periodic activity.
/// </summary>
protected abstract TimeSpan SubsequentInterval { get; }
/// <summary>
/// Override with a method that performs the desired periodic activity. If this method throws an exception
/// the thread will terminate, but the <see cref="LastActivity"/> will occur nevertheless.
/// </summary>
protected abstract void PeriodicActivity();
/// <summary>
/// Override with a method that performs an activity on the same thread as <see cref="PeriodicActivity"/> during
/// shutdown, just before signalling that the shutdown is complete. The default implementation of this method
/// does nothing. This method is guaranteed to be called during a shutdown, even if the shutdown is due to an
/// exception propagating outside of <see cref="PeriodicActivity"/>.
/// </summary>
protected virtual void LastActivity() { }
/// <summary>
/// Returns false before the first call to <see cref="Start"/> and after the first call to <see cref="Shutdown"/>;
/// true between them.
/// </summary>
public bool IsRunning { get { return _cancellation != null && !_cancellation.IsCancellationRequested; } }
/// <summary>
/// Schedules the periodic activity to start occurring. This method may only be called once.
/// </summary>
/// <param name="backgroundThread">By default (false) the class will use a foreground thread, preventing application shutdown until the thread has terminated. If true, a background thread will be created instead.</param>
public virtual void Start(bool backgroundThread = false)
{
if (_thread != null)
throw new InvalidOperationException(string.Format("\"Start\" called multiple times ({0})", GetType().Name));
_exited = new ManualResetEvent(false);
_cancellation = new CancellationTokenSource();
_thread = new Thread(threadProc) { IsBackground = backgroundThread };
_thread.Start();
}
private volatile bool _periodicActivityRunning = false;
/// <summary>
/// Causes the periodic activity to stop occurring. If called while the activity is being performed,
/// will wait until the activity has completed before returning. Ensures that <see cref="IsRunning"/>
/// is false once this method returns.
/// </summary>
public virtual bool Shutdown(bool waitForExit)
{
if (waitForExit && _periodicActivityRunning && Thread.CurrentThread.ManagedThreadId == _thread.ManagedThreadId)
throw new InvalidOperationException("Cannot call Shutdown(true) from within PeriodicActivity() on the same thread (this would cause a deadlock).");
if (_cancellation == null || _cancellation.IsCancellationRequested)
return false;
_cancellation.Cancel();
if (waitForExit)
_exited.WaitOne();
return true;
}
private void threadProc()
{
try
{
_cancellation.Token.WaitHandle.WaitOne(FirstInterval);
while (!_cancellation.IsCancellationRequested)
{
_periodicActivityRunning = true;
PeriodicActivity();
_periodicActivityRunning = false;
_cancellation.Token.WaitHandle.WaitOne(SubsequentInterval);
}
}
finally
{
try { LastActivity(); }
finally { _exited.Set(); }
}
}
}
/// <summary>
/// <para>Encapsulates a class performing multiple related yet independent tasks on the same thread
/// at a certain minimum interval each. Schedules the activity that is the most late at every opportunity,
/// but will never execute more than one activity at a time (as they all share the same thread).</para>
/// </summary>
public abstract class PeriodicMultiple : Periodic
{
/// <summary>
/// Used to define the activities to be executed periodically.
/// </summary>
protected sealed class Task
{
/// <summary>The activity to be performed.</summary>
public Action Action;
/// <summary>The mimimum interval at which this activity should be repeated. May be delayed arbitrarily though.</summary>
public TimeSpan MinInterval;
/// <summary>Stores the last time this activity was executed.</summary>
public DateTime LastExecuted;
/// <summary>Calculates by how much this activity has been delayed. Is used internally to pick the next activity to run. Returns negative values for activities that aren't due yet.</summary>
public TimeSpan DelayedBy()
{
if (LastExecuted == default(DateTime))
return TimeSpan.FromDays(1000) - MinInterval; // to run shortest interval first when none of the tasks have ever executed
else
return (DateTime.UtcNow - LastExecuted) - MinInterval;
}
}
/// <summary>If desired, override to provide a custom interval at which the scheduler
/// should re-check whether any activity is due to start. Defaults to 1 second.</summary>
protected override TimeSpan SubsequentInterval { get { return TimeSpan.FromSeconds(1); } }
/// <summary>Initialise this with the list of activities to be executed.</summary>
protected IList<Task> Tasks;
/// <summary>For internal use.</summary>
protected sealed override void PeriodicActivity()
{
TimeSpan maxDelay = TimeSpan.MinValue;
Task maxDelayTask = null;
foreach (var task in Tasks)
{
var delayedBy = task.DelayedBy();
if (maxDelay < delayedBy && delayedBy > TimeSpan.Zero)
{
maxDelay = delayedBy;
maxDelayTask = task;
}
}
if (maxDelayTask != null)
{
maxDelayTask.LastExecuted = DateTime.UtcNow;
maxDelayTask.Action();
}
}
}
The thread spends most of the time sleeping, but it does wake up every 1 second to check if a task is due. This 1 second interval is probably too short for intervals like 15 minutes, so reduce it to something like 30 seconds instead (that would be the SubsequentInterval).
Hope it's useful!
It makes very little sense to start x threads to do x jobs when you intentionally don't let them do any work at all for y minutes. Just have one thread do x jobs. It will take x times longer to complete the work (a bit less, actually) but that's no issue at all as long as that takes less than y minutes.
Additional benefits from this is that the service cannot easily impact the responsiveness of the machine, other cores remain available. And that your code becomes a heckofalot easier to implement and debug.
Use the System.Threading.Thread timer to activate the work. The callback runs on a threadpool thread. Starting and stopping the service is easy, just enable/disable that timer.
Do you really need those threads to run constantly and then wake up after x minutes? I think you may want to consider using an existing scheduler library like Quartz.NET which handle running the tasks for you.
I have two suggestions for you. First, for building your service, check out TopShelf. It removes all the pain of setting up a Windows service.
Second, you can use the Observable class to create a timer without resorting to writing Timer specific code or Quartz (a pain to configure!).
Here's some sample code:
public class MyService
{
private IDisposable Timer;
public void Start()
{
Timer = ObservableHelpers
.CreateMinutePulse(15) // check every 15 seconds if it's a new minute
.Subscribe(i => DoSomething());
}
public void Stop()
{
if(Timer != null)
{
Timer.Dispose();
Timer = null;
}
}
public void DoSomething()
{
// do your thing here
}
}
public static class ObservableHelpers
{
/// <summary>
/// Returns an observable that pulses every minute with the specified resolution.
/// The pulse occurs within the amount of time specified by the resolution (in seconds.)
/// Higher resolution (i.e. lower specified number of seconds) may affect execution speed.
/// </summary>
/// <returns></returns>
public static IObservable<int> CreateMinutePulse(int resolution)
{
return Observable
.Interval(TimeSpan.FromSeconds(resolution.SetWithinRange(1, 59)))
.Select(i => DateTime.Now.Minute)
.DistinctUntilChanged();
}
}
Well, I belive your problem seems to be solved with Producer Consumer Design pattern.
Producer will be the single main thread, and the all other threads will be the consumer thread.
From my opinion it will be best have independent threads than using thread pool.
Eg:
private Thread Worker;
public Consumer()
{
Worker = new Thread(ProcessMethod);
}
Now in processmethod you do what you have to do.
Create as many Consumer as you want.
I have a class that I've created to allow asynchronous sequential execution of tasks, using the ThreadPool as the means of execution. The idea is that I'll have multiple instances running serial tasks in the background, but I don't want to have a separate dedicated Thread for each instance. What I'd like to check is whether this class is actually thread safe. It's fairly brief, so I thought I'd run it by the experts here, in case I'm missing something obvious. I've omitted a few of the convenience overloads for different Action types.
/// <summary>
/// This class wraps ThreadPool.QueueUserWorkItem, but providing guaranteed ordering of queued tasks for this instance.
/// Only one task in the queue will execute at a time, with the order of execution matching the order of addition.
/// This is designed as a lighter-weight alternative to using a dedicated Thread for processing of sequential tasks.
/// </summary>
public sealed class SerialAsyncTasker
{
private readonly Queue<Action> mTasks = new Queue<Action>();
private bool mTaskExecuting;
/// <summary>
/// Queue a new task for asynchronous execution on the thread pool.
/// </summary>
/// <param name="task">Task to execute</param>
public void QueueTask(Action task)
{
if (task == null) throw new ArgumentNullException("task");
lock (mTasks)
{
bool isFirstTask = (mTasks.Count == 0);
mTasks.Enqueue(task);
//Only start executing the task if this is the first task
//Additional tasks will be executed normally as part of sequencing
if (isFirstTask && !mTaskExecuting)
RunNextTask();
}
}
/// <summary>
/// Clear all queued tasks. Any task currently executing will continue to execute.
/// </summary>
public void Clear()
{
lock (mTasks)
{
mTasks.Clear();
}
}
/// <summary>
/// Wait until all currently queued tasks have completed executing.
/// If no tasks are queued, this method will return immediately.
/// This method does not prevent the race condition of a second thread
/// queueing a task while one thread is entering the wait;
/// if this is required, it must be synchronized externally.
/// </summary>
public void WaitUntilAllComplete()
{
lock (mTasks)
{
while (mTasks.Count > 0 || mTaskExecuting)
Monitor.Wait(mTasks);
}
}
private void RunTask(Object state)
{
var task = (Action)state;
task();
mTaskExecuting = false;
RunNextTask();
}
private void RunNextTask()
{
lock (mTasks)
{
if (mTasks.Count > 0)
{
mTaskExecuting = true;
var task = mTasks.Dequeue();
ThreadPool.QueueUserWorkItem(RunTask, task);
}
else
{
//If anybody is waiting for tasks to be complete, let them know
Monitor.PulseAll(mTasks);
}
}
}
}
UPDATE: I've revised the code to fix the main bugs kindly pointed out by Simon. This passes unit tests now, but I still welcome observations.
Don't do it. (Or at least avoid building your own stuff.)
Use the System.Threading.Tasks stuff (new in .NET 4.0). Create your a Task[] (size depends on number of parallel tasks you want) and let them read work items from a BlockingCollection while waiting for a CancellationToken. Your WaitForAll implementation would trigger your token, and call Task.WaitAll(Task[]) which will block until all your tasks are done.
Here's my second answer assuming that you cant use .NET 4.0 (and want comments on your existing code).
QueueTask enqueues the first task, getting isFirstTask = true, and starts a new thread. However, another thread may enqueue something while the first thread is processing, and Count == 0 => isFirstTask = true, and yet another thread is spawned.
Also, WaitUntilAllComplete will hang indefinitely if the task execution throws an exception (which may not necessarily crash everything, depending on exception handling), causing it to skip the call to RunNextTask().
And your WaitUntilAllComplete just waits until there are no more enqueue tasks, not that those currently executing are actually executing (they could just be enqueued in the ThreadPool) or complete.
It's built in in 4.0
How to: Create a Task Scheduler That Limits the Degree of Concurrency
You can also use a custom scheduler to achieve functionality that the default scheduler does not provide, such as strict first-in, first-out (FIFO) execution order. The following example demonstrates how to create a custom task scheduler. This scheduler lets you specify the degree of concurrency.
I see a few issues your with your SerialAsyncTasker class, but it sounds like you might have a good grasp of those so I will not go into any details on that topic (I may edit my answer with more details later). You indicated in the comments that you cannot use .NET 4.0 features nor can you use the Reactive Extensions backport. I propose that you use the producer-consumer pattern with a single consumer on a dedicated thread. This would perfectly fit your requirement of asynchronously executing tasks sequentially.
Note: You will have to harden the code to support gracefully shutting down, handling exceptions, etc.
public class SerialAsyncTasker
{
private BlockingCollection<Action> m_Queue = new BlockingCollection<Action>();
public SerialAsyncTasker()
{
var thread = new Thread(
() =>
{
while (true)
{
Action task = m_Queue.Take();
task();
}
});
thread.IsBackground = true;
thread.Start();
}
public void QueueTask(Action task)
{
m_Queue.Add(task);
}
}
Too bad you cannot use the BlockingCollection from the .NET 4.0 BCL or Reactive Extension download, but no worries. It is actually not too hard to implement one yourself. You can use Stephen Toub's blocking queue as a starting point and just rename a few things.
public class BlockingCollection<T>
{
private Queue<T> m_Queue = new Queue<T>();
public T Take()
{
lock (m_Queue)
{
while (m_Queue.Count <= 0) Monitor.Wait(m_Queue);
return m_Queue.Dequeue();
}
}
public void Add(T value)
{
lock (m_Queue)
{
m_Queue.Enqueue(value);
Monitor.Pulse(m_Queue);
}
}
}
public class ParallelExcecuter
{
private readonly BlockingCollection<Task> _workItemHolder;
public ParallelExcecuter(int maxDegreeOfParallelism)
{
_workItemHolder = new BlockingCollection<Task>(maxDegreeOfParallelism);
}
public void Submit(Action action)
{
_workItemHolder.Add(Task.Run(action).ContinueWith(t =>
{
_workItemHolder.Take();
}));
}
public void WaitUntilWorkDone()
{
while (_workItemHolder.Count < 0)
{
Monitor.Wait(_workItemHolder);
}
}
}
Is this an appropriate way of handling cross-thread operations?
Should I use a new property name, something like "EditValueThreadSafe" instead of overriding "EditValue"? I don't think there is an issue with the changes to the implementation of EditValue, as the base property is called regardless.
namespace MyApplication.Components
{
using System.Windows.Forms;
/// <summary>
/// Thread-safe implementation of the DevExpress.XtraEditors.ComboBoxEdit class.
/// </summary>
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
/// <summary>
/// Gets or sets the edit value.
/// </summary>
/// <value>The edit value.</value>
public override object EditValue
{
get
{
return base.EditValue;
}
set
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(delegate
{
this.SetEditValue(value);
}));
}
else
{
this.SetEditValue(value);
}
}
}
/// <summary>
/// Sets the edit value.
/// </summary>
/// <param name="value">The value.</param>
private void SetEditValue(object value)
{
base.EditValue = value;
}
}
}
You can also delegate to another method that does the work, and in that method, if on the wrong thread, (BeginInvoke returns true), then call the same method back again. Doing that that eliminates the need to duplicate code.
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
public override object EditValue
{
get
{
return base.EditValue;
}
set
{
SetValue(value);
}
}
private void delegate SetValueDlg(object valeu);
private void SetValue(object value)
{
if (this.InvokeRequired)
this.BeginInvoke(
(SetValueDlg)SetValue, // calls itself, but on correct thread
new object[] { value });
else
base.editValue = value;
}
}
You can also use the Action() generic class to eliminate need to create explicit delegate class...
public class ComboBoxEditThreadSafe : DevExpress.XtraEditors.ComboBoxEdit
{
public override object EditValue
{
get { return base.EditValue; }
set { SetValue(value); }
}
private void SetValue(object value)
{
if (this.InvokeRequired)
this.BeginInvoke(
new Action<object>(SetValue), // calls itself, but on correct thread
new object[] { value });
else
base.editValue = value;
}
}
It's thread-safe, yes, though be wary of overriding a property and fundamentally changing the behaviour. Changing the implentation is fine, but this property now behaves very differently, removing the possibility of a specific exception but introducing a possible deadlock or blocking condition, which impacts on the calling code.
So yes, this is the correct use of InvokeRequired & Invoke, but I'd recommend creating a separate, purpose-specific and thread-safe property that is advertised as such.
My UI methods like yours end up looking like this:
public void setStatusLabelText(String s)
{
if (footerStatusLabel.InvokeRequired) {
StringUpdateInvokeDelegate callback = new StringUpdateInvokeDelegate(setStatusLabelText);
this.Invoke(callback, new object[] { s });
}
else {
this.footerStatusLabel.Text = s;
}
}
(this may be old for .net these days - but the point is that you can just do the operation inside this method if you are already on the right thread - makes it a little less irritating to read, but still annoying compared to Java, IMO).
I'll inject my 2 cents here. The actual calls to InvokeRequired/BeginInvoke/Invoke are not entirely thread safe. (see Avoiding the woes of Invoke/BeginInvoke in cross-thread WinForm event handling?) I would recommend finding some way of isolating the calls to these in a single place, utility api, extension method, or the like. In the article above there is complete code for a class that wraps a delegate to provide thread-safe behavior.