Run code only once using dispatcher - c#

I have a simple pattern to run code only once. It's mostly used to Update something on the UI, while it may change very often in the Background.
private bool _updating;
private void UpdateSomething()
{
if (!_updating)
{
_updating = true;
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
_updating = false;
DoSomething();
}), DispatcherPriority.Background);
}
}
I would prefer to put the boilerplate code inside a simple method:
public static void RunOnce(Action action, ref bool guard)
{
if (!guard)
{
guard = true;
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
guard = false;
action();
}), DispatcherPriority.Background);
}
}
und call it like this:
void UpdateSomething()
{
RunOnce(DoSomething, ref _updating);
}
However, this does not work as you cannot have ref parameters inside anonymous methods.
Is there any workaround, e.g. to pin the ref parameter and free it when the method was executed?

You could do something like this:
public static void RunOnce(Action action, ref RunOnceToken token)
{
if (token == null || token.IsCompleted)
{
token = new RunOnceToken(
Application.Current.Dispatcher.BeginInvoke(
action,
DispatcherPriority.Background));
}
}
public sealed class RunOnceToken : IDisposable
{
private DispatcherOperation _operation;
public RunOnceToken(DispatcherOperation operation)
{
if (operation != null &&
operation.Status != DispatcherOperationStatus.Completed &&
operation.Status != DispatcherOperationStatus.Aborted)
{
_operation = operation;
_operation.Completed += OnCompletedOrAborted;
_operation.Aborted += OnCompletedOrAborted;
}
}
private void OnCompletedOrAborted(object sender, EventArgs e)
{
this.Dispose();
}
public bool IsCompleted
{
get { return _operation == null; }
}
public void Dispose()
{
var operation = _operation;
if (operation == null)
return;
_operation = null;
operation.Completed -= OnCompletedOrAborted;
operation.Aborted -= OnCompletedOrAborted;
}
}
Your example usage would change to:
private RunOnceToken _updateToken;
private void UpdateSomething()
{
RunOnce(DoSomething, ref _updateToken);
}
It doesn't really matter if you never clear your copy of the token, because the wrapped DispatcherOperation gets cleared out upon completion to avoid leaking action or any values it captures.
In case it wasn't obvious, none of this is concurrency-safe; I assume everything above is only accessed from the UI thread.
One useful enhancement might be to add an optional DispatcherPriority argument to RunOnce such that you can control the priority level used to schedule action (perhaps canceling an already-scheduled operation if it was scheduled at a lower priority).

I was no aware about DispatcherOperation existence, however seen Mike Strobel answer I wrote following code. I'm not 100% sure about it but it seems to work without to much boilerplate.
public static class DispatcherExtensions {
public static int clearInterval = 10_000;
private static long time => DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
private static long lastClearTime = time;
private static Dictionary<int, DispatcherOperation> currOperations = new Dictionary<int, DispatcherOperation>();
private static object sync = new object();
public static void invokeLastAsync(this Dispatcher d, Action a, DispatcherPriority p = DispatcherPriority.Background, [CallerFilePath]object key1 = null, [CallerLineNumber]object key2 = null) {
lock (sync) {
DispatcherOperation dop;
var k = key1.GetHashCode() ^ key2.GetHashCode();
if (currOperations.ContainsKey(k)) {
dop = currOperations[k];
currOperations.Remove(k);
dop.Abort();
}
dop = d.BeginInvoke(a, p);
clearOperations(false);
currOperations.Add(k, dop);
}
}
public static void clearOperations(bool force = true) {
var ct = time;
if (!force && ct - lastClearTime < clearInterval) return;
var nd = new Dictionary<int, DispatcherOperation>();
foreach (var ao in currOperations) {
var s = ao.Value.Status;
if (s == DispatcherOperationStatus.Completed
|| s == DispatcherOperationStatus.Aborted)
nd.Add(ao.Key, ao.Value);
}
currOperations = nd;
lastClearTime = ct;
}
}
Basically extension method take file path and line number as a key to store DispacherOperation instance in a dictionary, and If the key already have an operation, its aborted and replaced with new operation. Periodically, the dictionary is cleared, from completed/aborted actions that are no longer invoked.
The usage is very simple:
private int initCount = 0;
private int invokeCount = 0;
private void updateSomething() {
initCount++;
view.Dispatcher.invokeLastAsync(() => {
Console.WriteLine($#"invoked {++invokeCount}/{initCount}");
});
}
I haven't run to any issue with this so far. Maybe someone else could see some weak spot.

Related

Monitor doesn't seem to lock the object

I'm trying to implement a basic Future class (yeah, I know about Task but this is for educational purposes) and ran into strange behavior of Monitor class. The class is implemented so that it enters the lock in constructor, queues an action which exits the lock to a thread pool. Result getter checks an instance variable to see if the action is completed and if it isn't, enters lock and then returns the result. Problem is that in fact result getter doesn't wait for the queued action to finish and proceeds anyway leading to incorrect results. Here's the code.
// The class itself
public class Future<T>
{
private readonly Func<T> _f;
private volatile bool _complete = false;
private T _result;
private Exception _error = new Exception("WTF");
private volatile bool _success = false;
private readonly ConcurrentStack<Action<T>> _callbacks = new ConcurrentStack<Action<T>>();
private readonly ConcurrentStack<Action<Exception>> _errbacks = new ConcurrentStack<Action<Exception>>();
private readonly object _lock = new object();
public Future(Func<T> f)
{
_f = f;
Monitor.Enter(_lock);
ThreadPool.QueueUserWorkItem(Run);
}
public void OnSuccess(Action<T> a)
{
_callbacks.Push(a);
if (_complete && _success)
a(_result);
}
public void OnError(Action<Exception> a)
{
_errbacks.Push(a);
if (_complete && !_success)
a(_error);
}
private void Run(object state)
{
try {
_result = _f();
_success = true;
_complete = true;
foreach (var cb in _callbacks) {
cb(_result);
}
} catch (Exception e) {
_error = e;
_complete = true;
foreach (var cb in _errbacks) {
cb(e);
}
} finally {
Monitor.Exit(_lock);
}
}
public T Result {
get {
if (!_complete) {
Monitor.Enter(_lock);
}
if (_success) {
return _result;
} else {
Console.WriteLine("Throwing error complete={0} success={1}", _complete, _success);
throw _error;
}
}
}
// Failing test
public void TestResultSuccess() {
var f = new Future<int>(() => 1);
var x = f.Result;
Assert.AreEqual (1, x);
}
I'm using Mono 3.2.3 on Mac OS X 10.9.
Only the thread that took the lock can exit the lock. You can't Enter it in the constructor on the calling thread then Exit from the thread-pool when it completes - the thread-pool worker does not have the lock.
And conversely: presumably it is the same thread that created the future that is accessing the getter: that is allowed to Enter again: it is re-entrant. Also, you need to Exit the same number of times that you Enter, otherwise it isn't actually released.
Basically, I don't think Monitor is the right approach here.

Using C# 5 async to wait for something that executes over a number of game frames

My son is writing a simple RPG game that has a number of non-player characters (aka NPC's). Each NPC has an associated "script" that controls its behaviour. We were going to use a mini custom script language to write these behaviours but I'm now wondering if this would be better done in C#5/Async.
Taking a really simple example, suppose one of the NPC's just walks between two points I'm thinking it would be nice to write something like this:
while (true)
{
await WalkTo(100,100);
await WalkTo(200,200);
}
The WalkTo method would be an async method that handles everything to do with walking between the two points and does this over a number of frames from the game loop. It's not a blocking method that can be off-loaded to a background thread.
And this is where I'm stuck... I haven't been able to find any examples using async/await in this manner, but it seems it would be perfect for it.
Ideas?
Here's some very rough pseudo code for what I'd like to do:
class NpcBase
{
// Called from game loop
public void onUpdate(double elapsedTime)
{
// Move the NPC
.
.
.
// Arrived at destination?
if (Arrived)
{
// How do I trigger that the task is finished?
_currentTask.MarkComplete();
}
}
// Async method called by NPC "script"
public async Task WalkTo(int x, int y)
{
// Store new target location
// return a task object that will be "triggered" when the walk is finished
_currentTask = <something??>
return _currentTask;
}
Task _currentTask;
}
Okay, it sounds like one option would be to have a TaskCompletionSource for each frame of the game. You can then await the Task from WalkTo, and set the result in OnUpdate:
private TaskCompletionSource<double> currentFrameSource;
// Called from game loop
public void OnUpdate(double elapsedTime)
{
...
var previousFrameSource = currentFrameSource;
currentFrameSource = new TaskCompletionSource<double>();
// This will trigger all the continuations...
previousFrameSource.SetResult(elapsedTime);
}
// Async method called by NPC "script"
public async Task WalkTo(int x, int y)
{
// Store new target location
while (/* we're not there yet */)
{
double currentTime = await currentFrameSource.Task;
// Move
}
}
I'm not sure how efficient this will be, admittedly... but it should work.
I think I've figured it out in a simple test program
Firstly, I've got a base class for the NPC's like this:
EDIT: Updated NpcBase to use TaskCompletionSource:
public class NpcBase
{
// Derived classes to call this when starting an async operation
public Task BeginTask()
{
// Task already running?
if (_tcs!= null)
{
throw new InvalidOperationException("busy");
}
_tcs = new TaskCompletionSource<int>();
return _tcs.Task;
}
TaskCompletionSource<int> _tcs;
// Derived class calls this when async operation complete
public void EndTask()
{
if (_tcs != null)
{
var temp = _tcs;
_tcs = null;
temp.SetResult(0);
}
}
// Is this NPC currently busy?
public bool IsBusy
{
get
{
return _tcs != null;
}
}
}
For reference, here's the old version of NpcBase with custom IAsyncResult implementation instead of TaskCompletionSource:
// DONT USE THIS, OLD VERSION FOR REFERENCE ONLY
public class NpcBase
{
// Derived classes to call this when starting an async operation
public Task BeginTask()
{
// Task already running?
if (_result != null)
{
throw new InvalidOperationException("busy");
}
// Create the async Task
return Task.Factory.FromAsync(
// begin method
(ac, o) =>
{
return _result = new Result(ac, o);
},
// End method
(r) =>
{
},
// State object
null
);
}
// Derived class calls this when async operation complete
public void EndTask()
{
if (_result != null)
{
var temp = _result;
_result = null;
temp.Finish();
}
}
// Is this NPC currently busy?
public bool IsBusy
{
get
{
return _result != null;
}
}
// Result object for the current task
private Result _result;
// Simple AsyncResult class that stores the callback and the state object
class Result : IAsyncResult
{
public Result(AsyncCallback callback, object AsyncState)
{
_callback = callback;
_state = AsyncState;
}
private AsyncCallback _callback;
private object _state;
public object AsyncState
{
get { return _state; ; }
}
public System.Threading.WaitHandle AsyncWaitHandle
{
get { throw new NotImplementedException(); }
}
public bool CompletedSynchronously
{
get { return false; }
}
public bool IsCompleted
{
get { return _finished; }
}
public void Finish()
{
_finished = true;
if (_callback != null)
_callback(this);
}
bool _finished;
}
}
Next, I've got a simple "NPC" that moves in one dimension. When a moveTo operation starts it calls BeginTask in the NpcBase. When arrived at the destination, it calls EndTask().
public class NpcTest : NpcBase
{
public NpcTest()
{
_position = 0;
_target = 0;
}
// Async operation to count
public Task MoveTo(int newPosition)
{
// Store new target
_target = newPosition;
return BeginTask();
}
public int Position
{
get
{
return _position;
}
}
public void onFrame()
{
if (_position == _target)
{
EndTask();
}
else if (_position < _target)
{
_position++;
}
else
{
_position--;
}
}
private int _position;
private int _target;
}
And finally, a simple WinForms app to drive it. It consists of a button and two labels. Clicking the button starts both NPC and their position is displayed on the labels.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void onButtonClick(object sender, EventArgs e)
{
RunNpc1();
RunNpc2();
}
public async void RunNpc1()
{
while (true)
{
await _npc1.MoveTo(20);
await _npc1.MoveTo(10);
}
}
public async void RunNpc2()
{
while (true)
{
await _npc2.MoveTo(80);
await _npc2.MoveTo(70);
}
}
NpcTest _npc1 = new NpcTest();
NpcTest _npc2 = new NpcTest();
private void timer1_Tick(object sender, EventArgs e)
{
_npc1.onFrame();
_npc2.onFrame();
label1.Text = _npc1.Position.ToString();
label2.Text = _npc2.Position.ToString();
}
}
And it works, all seems to be running on the main UI thread... which is what I wanted.
Of course it needs to be fixed to handle cancelling of operations, exceptions etc... but the basic idea is there.

What is a good way to parallelize many HTTP web requests?

I am building a generic URI retrieval system. Essentially there's a generic class Retriever<T> and it maintains a queue of URIs to be retrieved. It has a separate thread that handles that queue as fast as it can. An example of a type of URI, as indicated in the question title, is HTTP type URIs.
The problem is, when I get down to requesting that the resource be retrieved, via an abstract method T RetrieveResource(Uri location), it slow down due to a lack of asynchrony.
Changing the return type of RetrieveResource to Task<T> was my first thought. However, that seems to make tasks pile up and cause lots of problems when we have thousands of outstanding tasks. It appears to create many actual threads instead of utilizing the thread pool. I imagine this just slows everything down because there are too many things going on at once, so nothing individually is making significant progress.
It's expected that we will have a large number of queued items to retrieve and that they cannot be handled as fast as they are enqueued. There is an opportunity for the system to catch up, over time; but it's definitely not quick.
I've also thought about instead of maintaining a queue and a thread to handle it... to just queue a work item on the ThreadPool. However, I'm not sure that this is ideal if say I need to shut the system down before all work items are handled or later want to allow for prioritization or something.
We also know that retrieving a resource is a time consuming process (0.250 - 5 seconds), but not necessarily a resource intense process. We are fine parallelizing this out to hundreds of requests.
Our requirements are:
URIs can be enqueued from any thread, even when the system is working on the queue
Retrieval may need to later be capable of being prioritized
Retrieval should be able to be paused
Minimal spinning should occur when nothing is being retrieved (BlockingCollection is useful here).
Is there a good way to parallelize this without introducing unnecessary complexity?
Below is some existing code we have, as an example.
public abstract class Retriever<T> : IRetriever<T>, IDisposable
{
private readonly Thread worker;
private readonly BlockingCollection<Uri> pending;
private volatile int isStarted;
private volatile int isDisposing;
public event EventHandler<RetrievalEventArgs<T>> Retrieved;
protected Retriever()
{
this.worker = new Thread(this.RetrieveResources);
this.pending = new BlockingCollection<Uri>(new ConcurrentQueue<Uri>());
this.isStarted = 0;
this.isDisposing = 0;
}
~Retriever()
{
this.Dispose(false);
}
private void RetrieveResources()
{
while (this.isDisposing == 0)
{
while (this.isStarted == 0)
{
Monitor.Wait(this.pending);
}
Uri location = this.pending.Take();
// This is what needs to be concurrently done.
// In this example, it's synchronous, but just on a separate thread.
T result = this.RetrieveResource(location);
// At this point, we would fire our event with the retrieved data
}
}
protected abstract T RetrieveResource(Uri location);
protected void Dispose(bool disposing)
{
if (Interlocked.CompareExchange(ref this.isDisposing, 1, 0) == 1)
{
return;
}
if (disposing)
{
this.pending.CompleteAdding();
this.worker.Join();
}
}
public void Add(Uri uri)
{
try
{
this.pending.Add(uri);
}
catch (InvalidOperationException)
{
return;
}
}
public void AddRange(IEnumerable<Uri> uris)
{
foreach (Uri uri in uris)
{
try
{
this.pending.Add(uri);
}
catch (InvalidOperationException)
{
return;
}
}
}
public void Start()
{
if (Interlocked.CompareExchange(ref this.isStarted, 1, 0) == 1)
{
throw new InvalidOperationException("The retriever is already started.");
}
if (this.worker.ThreadState == ThreadState.Unstarted)
{
this.worker.Start();
}
Monitor.Pulse(this.pending);
}
public void Stop()
{
if (Interlocked.CompareExchange(ref this.isStarted, 0, 1) == 0)
{
throw new InvalidOperationException("The retriever is already stopped.");
}
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
}
To build on the example above... a solution to this that I think adds too much complexity or rather, weird code... would be this.
private void RetrieveResources()
{
while (this.isDisposing == 0)
{
while (this.isStarted == 0)
{
Monitor.Wait(this.pending);
}
Uri location = this.pending.Take();
Task<T> task = new Task<T>((state) =>
{
return this.RetrieveResource(state as Uri);
}, location);
task.ContinueWith((t) =>
{
T result = t.Result;
RetrievalEventArgs<T> args = new RetrievalEventArgs<T>(location, result);
EventHandler<RetrievalEventArgs<T>> callback = this.Retrieved;
if (!Object.ReferenceEquals(callback, null))
{
callback(this, args);
}
});
task.Start();
}
}
I've come up with a pretty good solution I think. I abstracted both the method a resource is retrieved and the result's representation. This allows support for retrieval of arbitrary URIs with arbitrary results; kind of like some URI driven "ORM".
It supports variable concurrency levels. The other day when I posted the question, I was forgetting that asynchrony and concurrency are quite different and that all I was achieving with tasks was asynchrony and jamming up the task scheduler because what I really wanted was concurrency.
I added in cancellation because it seemed like a good idea to have start/stop capabilities.
public abstract class Retriever<T> : IRetriever<T>
{
private readonly object locker;
private readonly BlockingCollection<Uri> pending;
private readonly Thread[] threads;
private CancellationTokenSource cancellation;
private volatile int isStarted;
private volatile int isDisposing;
public event EventHandler<RetrieverEventArgs<T>> Retrieved;
protected Retriever(int concurrency)
{
if (concurrency <= 0)
{
throw new ArgumentOutOfRangeException("concurrency", "The specified concurrency level must be greater than zero.");
}
this.locker = new object();
this.pending = new BlockingCollection<Uri>(new ConcurrentQueue<Uri>());
this.threads = new Thread[concurrency];
this.cancellation = new CancellationTokenSource();
this.isStarted = 0;
this.isDisposing = 0;
this.InitializeThreads();
}
~Retriever()
{
this.Dispose(false);
}
private void InitializeThreads()
{
for (int i = 0; i < this.threads.Length; i++)
{
Thread thread = new Thread(this.ProcessQueue)
{
IsBackground = true
};
this.threads[i] = thread;
}
}
private void StartThreads()
{
foreach (Thread thread in this.threads)
{
if (thread.ThreadState == ThreadState.Unstarted)
{
thread.Start();
}
}
}
private void CancelOperations(bool reset)
{
this.cancellation.Cancel();
this.cancellation.Dispose();
if (reset)
{
this.cancellation = new CancellationTokenSource();
}
}
private void WaitForThreadsToExit()
{
foreach (Thread thread in this.threads)
{
thread.Join();
}
}
private void ProcessQueue()
{
while (this.isDisposing == 0)
{
while (this.isStarted == 0)
{
Monitor.Wait(this.locker);
}
Uri location;
try
{
location = this.pending.Take(this.cancellation.Token);
}
catch (OperationCanceledException)
{
continue;
}
T data;
try
{
data = this.Retrieve(location, this.cancellation.Token);
}
catch (OperationCanceledException)
{
continue;
}
RetrieverEventArgs<T> args = new RetrieverEventArgs<T>(location, data);
EventHandler<RetrieverEventArgs<T>> callback = this.Retrieved;
if (!Object.ReferenceEquals(callback, null))
{
callback(this, args);
}
}
}
private void ThowIfDisposed()
{
if (this.isDisposing == 1)
{
throw new ObjectDisposedException("Retriever");
}
}
protected abstract T Retrieve(Uri location, CancellationToken token);
protected virtual void Dispose(bool disposing)
{
if (Interlocked.CompareExchange(ref this.isDisposing, 1, 0) == 1)
{
return;
}
if (disposing)
{
this.CancelOperations(false);
this.WaitForThreadsToExit();
this.pending.Dispose();
}
}
public void Start()
{
this.ThowIfDisposed();
if (Interlocked.CompareExchange(ref this.isStarted, 1, 0) == 1)
{
throw new InvalidOperationException("The retriever is already started.");
}
Monitor.PulseAll(this.locker);
this.StartThreads();
}
public void Add(Uri location)
{
this.pending.Add(location);
}
public void Stop()
{
this.ThowIfDisposed();
if (Interlocked.CompareExchange(ref this.isStarted, 0, 1) == 0)
{
throw new InvalidOperationException("The retriever is already stopped.");
}
this.CancelOperations(true);
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
}

marshalling events to ui thread using Synchronisation Context

All the examples I have seen using SynchronisationContext.Post have been used in the same class. What I have is the UI thread passing some by-ref arguments to a threadwrapper class, updating the arguments and then I want it to update some labels etc on the UIThread.
internal class ConnThreadWrapper
{
....
public event EventHandler<MyEventArgs<String, Boolean>> updateConnStatus =
delegate { };
public void updateUIThread(string conn, bool connected)
{
uiContext.Post(new SendOrPostCallback((o) =>
{
updateConnStatus(this,
new MyEventArgs<String, Boolean>(conn,
connected));
}),
null);
}
}
//on ui thread
public void updateConnStatus(object sender, MyEventArgs<String, Boolean> e)
{
switch (e.val1)
{
case "CADS" :
if (e.val2 == true)
{
}
The Event seems to fire without any errors but nothing is ever received on the uiThread - i'm not sure if my signature for the sub updateConnStatus is correct or if it works like this. I obviously want the event to handled on the uithread and update the labels from that sub.
In a previous vb.net project I used to reference the form directly on the thread and used a delegate to invoke a callback but apparently this was a bad design as I was mixing application layers. I wanted to use the sync context as it was meant to be thread safe but most of the examples i've seen have used invoke.
Any ideas what I'm missing? Thanks
I wrote this helper class which works for me. Prior to using this class call InitializeUiContext() on UI thread somewhere on application start.
public static class UiScheduler
{
private static TaskScheduler _scheduler;
private static readonly ConcurrentQueue<Action> OldActions =
new ConcurrentQueue<Action>();
public static void InitializeUiContext()
{
_scheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
private static void ExecuteOld()
{
if(_scheduler != null)
{
while(OldActions.Count > 0)
{
Action a;
if(OldActions.TryDequeue(out a))
{
UiExecute(_scheduler, a);
}
}
}
}
private static void UiExecute(TaskScheduler scheduler,
Action a,
bool wait = false)
{
//1 is usually UI thread, dunno how to check this better:
if (Thread.CurrentThread.ManagedThreadId == 1)
{
a();
}
else
{
Task t = Task.Factory.StartNew(a,
CancellationToken.None,
TaskCreationOptions.LongRunning,
scheduler);
if (wait) t.Wait();
}
}
public static void UiExecute(Action a, bool wait = false)
{
if (a != null)
{
if (_scheduler != null)
{
ExecuteOld();
UiExecute(_scheduler, a, wait);
}
else
{
OldActions.Enqueue(a);
}
}
}
}
In the end I ditched the ThreadWrapper and trying to marshal the event to the UI Thread and used a Task instead, in fact I think I can use task to do most of the stuff in this project so happy days.
Task<bool> t1 = new Task<bool>(() => testBB(ref _bbws_wrapper));
t1.Start();
Task cwt1 = t1.ContinueWith(task => { if (t1.Result == true) { this.ssi_bb_conn.BackColor = Color.Green;} else { this.ssi_bb_conn.BackColor = Color.Red; } }, TaskScheduler.FromCurrentSynchronizationContext());
.....
private static bool testBB(ref BBWebserviceWrapper _bbwsw)
{
try
{
//test the connections
if (_bbwsw.initialize_v1() == true)
{
if (_bbwsw.loginUser("XXXXXXXX", "XXXXXXXXX") == true)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
catch
{
return false;
}
}

Thread Pooling help

Having some issue with Threadpooling here that I need some help with please. I am trying to write a Generator, and I need to allow users generate up to 10,000 lines with the code below. Problem with this is the line
WaitHandle.WaitAll(doneEvents);
Can only handle 64 WaitAll at a time, How can I best apply thread pooling to my code in this case?
public void GenerateInsertStatements(int iRequiredRows)
{
// One event is used for each row object
ManualResetEvent[] doneEvents = new ManualResetEvent[iRequiredRows];
Row[] rows = new Row[iRequiredRows];
for (int i = 0; i < iRequiredRows; i++)
{
doneEvents[i] = new ManualResetEvent(false);
Row row = new Row(this.Name, this.TableColumns, doneEvents[i]);
rows[i] = row;
ThreadPool.QueueUserWorkItem(row.ThreadPoolCallback, i);
}
WaitHandle.WaitAll(doneEvents);
using (sr = new StreamWriter(this.Name + ".sql"))
{
for(int i=0; i<rows.Length; i++)
{
WriteStatementToFile(i, rows[i].GeneratedInsertStatement);
}
}
}
Thanks in advance
I would use just one WaitHandle and one int. Like:
int done_when_zero; // This is a field of the class
ManualResetEvent evt = new ManualResetEvent (false); // Field
...
done_when_zero = iRequiredRows; // This goes before the loop
...
evt.WaitOne (); // this goes after the loop
evt.Reset (); // Prepare for next execution if needed
And then, at the end of ThreadPoolCallback:
if (Interlocked.Decrement (ref done_when_zero)) <= 0)
evt.Set ();
As it was already suggested using a counter and a single ManualResetEvent should work fine for you. Below is ThreadPoolWait class taken from .NET Matters: ThreadPoolWait and HandleLeakTracer (see Figure 3 Better Implementation of ThreadPoolWait for more info)
public class ThreadPoolWait : IDisposable
{
private int _remainingWorkItems = 1;
private ManualResetEvent _done = new ManualResetEvent(false);
public void QueueUserWorkItem(WaitCallback callback)
{
QueueUserWorkItem(callback, null);
}
public void QueueUserWorkItem(WaitCallback callback, object state)
{
ThrowIfDisposed();
QueuedCallback qc = new QueuedCallback();
qc.Callback = callback;
qc.State = state;
lock (_done) _remainingWorkItems++;
ThreadPool.QueueUserWorkItem(new WaitCallback(HandleWorkItem), qc);
}
public bool WaitOne() { return WaitOne(-1, false); }
public bool WaitOne(TimeSpan timeout, bool exitContext)
{
return WaitOne((int)timeout.TotalMilliseconds, exitContext);
}
public bool WaitOne(int millisecondsTimeout, bool exitContext)
{
ThrowIfDisposed();
DoneWorkItem();
bool rv = _done.WaitOne(millisecondsTimeout, exitContext);
lock (_done)
{
if (rv)
{
_remainingWorkItems = 1;
_done.Reset();
}
else _remainingWorkItems++;
}
return rv;
}
private void HandleWorkItem(object state)
{
QueuedCallback qc = (QueuedCallback)state;
try { qc.Callback(qc.State); }
finally { DoneWorkItem(); }
}
private void DoneWorkItem()
{
lock (_done)
{
--_remainingWorkItems;
if (_remainingWorkItems == 0) _done.Set();
}
}
private class QueuedCallback
{
public WaitCallback Callback;
public object State;
}
private void ThrowIfDisposed()
{
if (_done == null) throw new ObjectDisposedException(GetType().Name);
}
public void Dispose()
{
if (_done != null)
{
((IDisposable)_done).Dispose();
_done = null;
}
}
}
Probably not the most efficient solution, but it should work regardless of the 64 wait handles limit :
for(int i = 0; i < iRequiredRows; i++)
doneEvents[i].WaitOne();

Categories