Multiple events and multi threading - c#

I have a service that raises multiple events, some of them can be raised at the same time. I need to process those events and run a potentially long running method based on the event arguments.
What I did is to create a BlockingCollection<T> that will store the events an a Task that will keep taking one event at a time until it will be signaled to stop using a CancellationTokenSource.
My concern is that I'm not handling the synchronization good enough.
This is the class that handles everything (it's used as a WPF ViewModel):
public class EventsTest
{
//private fields
private BlockingCollection<IoEventArgs> _queue;
private CancellationTokenSource _tokenSource;
private IoService _ioService;
private Task _workerTask;
private static EventWaitHandle _eventWaiter;
public EventsTest()
{
_queue = new BlockingCollection<IoEventArgs>();
_tokenSource = new CancellationTokenSource();
_eventWaiter = new EventWaitHandle(false, EventResetMode.AutoReset);
//this is the object that raises multiple events
_ioService = new IoService();
_ioService.IoEvent += _ioService_IoEvent;
//Start Listening
var t = Task.Factory.StartNew(StartListening, _tokenSource, TaskCreationOptions.LongRunning);
}
//IO events listener
private void _ioService_IoEvent(string desc, int portNum)
{
//add events to a blocking collection
_queue.Add(new IoEventArgs() { Description = desc, PortNum = portNum });
}
private void StartListening(object dummy)
{
//process the events one at a time
while (!_tokenSource.IsCancellationRequested)
{
var eve = _queue.Take();
switch (eve.PortNum)
{
case 0:
LongRunningMethod(eve.Description);
break;
case 1:
//invoke a long running method
break;
default:
break;
}
}
}
//sample long running method
private void LongRunningMethod(string data)
{
_eventWaiter.WaitOne(10000);
}
}
How can I make this process more robust in terms of thread safety?
Will adding a lock around each method implementation improve the safety of the process?

Your .Take() won't be canceled so you might wait forever there.
You could pass the token on:
var eve = _queue.Take(_tokenSource);
but then you would have to handle the exception.
A better approach would be the TryTake(out eve, 1000, _tokenSource) and steer with the returned boolean.
Or forget about the CancellationToken and just use AddingComplete()

This sounds like a situation where Microsoft's Reactive Framework is a far better fit.
Your code would look like this:
public class EventsTest
{
private IDisposable _subscription;
public EventsTest()
{
IoService ioService = new IoService();
_subscription =
Observable
.FromEvent<IoEvent, IoEventArgs>(
a => ioService.IoEvent += a, a => ioService.IoEvent -= a)
.Subscribe(eve =>
{
switch (eve.PortNum)
{
case 0:
LongRunningMethod(eve.Description);
break;
case 1:
//invoke a long running method
break;
default:
break;
}
});
}
private void LongRunningMethod(string data)
{
}
}
This should automatically ensure multiple events are queued and will never overlap. If there's problem just drop a .Synchronize() call in before the .Subscribe(...) and then it'll work perfectly.
When you want to cancel the event just call _subscription.Dispose() and it will all be cleaned up for you.
NuGet "Rx-Main" to get the bits you need.

Related

How to reduce frequency of continuously fired event's event handling

I am learning about tasks and async/await in c#. So please consider the stupidity of my question.
There is an event DummyEvent in a class. An event handler DummyEventHandler is subscribed to this event and it handles a large amount of CPU bound task, which is actually not needed to be used so frequently.
For that reason, if DummyEvent is fired continuously, I want DummyEventHandler to respond either at a reduced frequency, or respond at the end of that continuity.
So, my idea is to extract the large task into a separate Task and made it to delay 500 millisecond before it proceeds. After the delay ends, it will check whether the same Task has been scheduled again (continuous event fire) or not and avoid the large calculation if true.
Here is my naive implementation of that idea:
int ReducedCall = 0;
int TotalCallActual = 0;
protected void DummyEventHandler(object sender, bool arg)
{
TotalCallActual++;
LargeCPUBoundTask(); // there is a green underline here, but I think it's ok, or.. is it?
}
async Task LargeCPUBoundTask()
{
ReducedCall = TotalCallActual;
await Task.Delay(500);
// if this task is called again in this time, TotalCallActual will increase
if (ReducedCall == TotalCallActual)
{
// do all the large tasks
……
ReducedCall = 0;
TotalCallActual = 0;
}
}
But the problem is, I am not getting what I want. The line Task.Delay(500) doesn't actually await , or, if it does wait, there is something wrong because I experience staggering .
Any better idea, or any improvement / correction?
Ask for any additional information.
Thanks
You can leverage Reactive Extensions to do this:
void Main()
{
var generator = new EventGenerator();
var observable = Observable.FromEventPattern<EventHandler<bool>, bool>(
h => generator.MyEvent += h,
h => generator.MyEvent -= h);
observable
.Throttle(TimeSpan.FromSeconds(1))
.Subscribe(s =>
{
Console.WriteLine("doing something");
});
// simulate rapid firing event
for(int i = 0; i <= 100; i++)
generator.RaiseEvent();
// when no longer interested, dispose the subscription
subscription.Dispose();
}
public class EventGenerator
{
public event EventHandler<bool> MyEvent;
public void RaiseEvent()
{
if (MyEvent != null)
{
MyEvent(this, false);
}
}
}
The Throttle operator as coded above will allow a value (event) getting true every second.
So in the above code example the text doing something will only be printed once (after a second) even while the event is fired many times.
Edit
By the way, the reason for the green line is that your Task is not awaited. To fix it alter the code to:
protected async void DummyEventHandler(object sender, bool arg)
{
TotalCallActual++;
await LargeCPUBoundTask(); // there is no more green underline here
}
Unfortunately this will still not solve your issue as an event cannot be awaited so if the event is raised again while LargeCPUBoundTask is still running another call to LargeCPUBoundTask will be made so the work is overlapping if you get what I mean. In other words, that is why your code does not work.
I would use the timer event handler instead of your DummyEventHandler
Just adjust the frequency in milisencond of the timer and that will be it. You can create a timer via code without adding it to a form as a control. I think it is in the common controls lib.
Hope this helps. Good luck.
I spent some more time thinking about this problem and the assumption I made with my first solution was that the event is continuously firing, when it could just be firing part of the time for a while and then stop in the real problem.
In cases like this, the CPU bound task would only occur on the first event firing and then if the events finish firing before that CPU bound task completes, the remaining events would not get handled. But you wouldn't want to handle all of them, just the "last" one (not necessarily the actual last one, just one more to take care of the "cleanup").
So I've updated my answer to include the use case where there are frequent yet intermittent (i.e. burst of events then quiet) the correct thing would occur and a final run of the CPU bound task would happen (but still no more than 1 CPU bound task running at a time).
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
Sender s = new Sender();
using (Listener l = new Listener(s))
{
s.BeginDemonstration();
}
}
}
class Sender
{
const int ATTEMPTED_CALLS = 1000000;
internal EventHandler frequencyReducedHandler;
internal int actualCalls = 0;
internal int ignoredCalls = 0;
Task[] tasks = new Task[ATTEMPTED_CALLS];
internal void BeginDemonstration()
{
int attemptedCalls;
for (attemptedCalls = 0; attemptedCalls < ATTEMPTED_CALLS; attemptedCalls++)
{
tasks[attemptedCalls] = Task.Run(() => frequencyReducedHandler.Invoke(this, EventArgs.Empty));
//frequencyReducedHandler?.BeginInvoke(this, EventArgs.Empty, null, null);
}
if (tasks[0] != null)
{
Task.WaitAll(tasks, Timeout.Infinite);
}
Console.WriteLine($"Attempted: {attemptedCalls}\tActual: {actualCalls}\tIgnored: {ignoredCalls}");
Console.ReadKey();
}
}
class Listener : IDisposable
{
enum State
{
Waiting,
Running,
Queued
}
private readonly AutoResetEvent m_SingleEntry = new AutoResetEvent(true);
private readonly Sender m_Sender;
private int m_CurrentState = (int)State.Waiting;
internal Listener(Sender sender)
{
m_Sender = sender;
m_Sender.frequencyReducedHandler += Handler;
}
private async void Handler(object sender, EventArgs args)
{
int state = Interlocked.Increment(ref m_CurrentState);
try
{
if (state <= (int)State.Queued) // Previous state was WAITING or RUNNING
{
// Ensure only one run at a time
m_SingleEntry.WaitOne();
try
{
// Only one thread at a time here so
// no need for Interlocked.Increment
m_Sender.actualCalls++;
// Execute CPU intensive task
await Task.Delay(500);
}
finally
{
// Allow a waiting thread to proceed
m_SingleEntry.Set();
}
}
else
{
Interlocked.Increment(ref m_Sender.ignoredCalls);
}
}
finally
{
Interlocked.Decrement(ref m_CurrentState);
}
}
public void Dispose()
{
m_SingleEntry?.Dispose();
}
}

background/Asynchronous process using Threading or Delegate

At My website
1. After filling form Inserting that record in SQL database
2. In Next Line I take some class object then send to Matching with other record
3. In matching application taking so much time
Now I have decided I will put matching process in background/Asynchronous by using Threading or Delegate
My Previous code was:
1. Inserting all information in database
objclsBbDAL.InsertAcquirePrvider(objAcqProvBL);
2. Matching related record with other record in database
clsMatchMakingDAL objclsMatchMakingDAL = new clsMatchMakingDAL();
objclsMatchMakingDAL.AcquireMatch(objAcqProvBL);
Q 1. Which one is best way to run process in background/Asynchronous - Threading or Delegate
Now I am using Threading:
objclsBbDAL.InsertAcquirePrvider(objAcqProvBL);
//Threading
CallMatchMakingOnDiffThread(objAcqProvBL);
private void CallMatchMakingOnDiffThread(clsAcquireProviderBL objAcqPro)
{
clsMatchMakingDAL objclsMatchMakingDAL = new clsMatchMakingDAL();
Thread objThread = new Thread(() => objclsMatchMakingDAL.AcquireMatch(objAcqPro));
objThread.Start();
}
Q2. How can do this task with Delegate?
Delegates are like callbacks, you use them to notify that an asynchronous task has been completed, meaning the thread needs to call an event, which should have a delegate hooked onto it.
For example:
public struct ThreadData
{
public int handle;
public string details;
public ThreadData(int handle, string details)
{
this.handle = handle;
this.details = details;
}
}
public class ThreadWorker
{
private List<Thread> threads = new List<Thread>();
public int BeginAsyncWork(string details)
{
Thread thread = new Thread(new ParameterizedThreadStart(ThreadMethod));
threads.Add(thread);
thread.Start(new ThreadData(threads.Count - 1, details));
return threads.Count - 1;
}
private void ThreadMethod(object parameter)
{
ThreadData data = (ThreadData)parameter;
Console.WriteLine(data.details);
if (ThreadFinished != null) { ThreadFinished(data.handle); }
}
public delegate void ThreadEndDelegate(int handle);
public event ThreadEndDelegate ThreadFinished;
}
public static class Program
{
private static int[] handles;
public static void Main()
{
handles = new int[4];
ThreadWorker worker = new ThreadWorker();
worker.ThreadFinished += new ThreadWorker.ThreadEndDelegate(OnThreadFinished);
for (int i = 0; i < 4; i++)
{
handles[i] = worker.BeginAsyncWork("working: " + i);
}
Console.ReadKey();
}
private static void OnThreadFinished(int handle)
{
Console.WriteLine("thread: " + handle + " finished");
handles[handle] = 0;
}
}
It's long winded but it allows for full control over your threads.
EDIT:
Untested code. The shortest possible solution I could think of.
objclsBbDAL.InsertAcquirePrvider(objAcqProvBL);
//Threading
CallMatchMakingOnDiffThread(objAcqProvBL);
private void OnMatchAcquired(object match)
{
//do work with found match
}
private event Action<object> MatchAcquired = new Action<object>(OnMatchAcquired);
private void CallMatchMakingOnDiffThread(clsAcquireProviderBL objAcqPro)
{
clsMatchMakingDAL objclsMatchMakingDAL = new clsMatchMakingDAL();
Thread objThread = new Thread(
() => object match = (object)objclsMatchMakingDAL.AcquireMatch(objAcqPro); if(ThreadComplete!=nil){MatchAcquired(match);}
);
objThread.Start();
}
You can not do background processing with only a delegate.
A delegate is totally different from a thread or an asynchronous process.
You can understand a delegate as a pointer to a function.
Threads use delegates to execute a certain function but delegates alone are not any kind of background execution.
Doing what you mentioned up-there would run the process in background, but you have to know the costs for running the operation in background and in this way. You also need to know if it does really needs to be run in background or it only needs optimization.
The easyest way (for me at least) is to use a delegate and BeginInvoke, which will return immediately and for which you can supply a callback that is executed when the delegate is finished.
More info on MSDN.
In your sample code I do not see, that you need to be notified, when the operation is finished so you could do something like this:
new Action(() =>
{
clsMatchMakingDAL objclsMatchMakingDAL = new clsMatchMakingDAL();
objclsMatchMakingDAL.AcquireMatch(objAcqPro);
}).BeginInvoke(null, null);
This would execute the matching functionality on another thread that is managed by .Net for you. If you need to be notified on completion, then the first argument to the BeginInvoke call could be another delegate to handle the completion event.

Using RX to synchronize multiple events

Let's say I have three products in a list. In order to enable a certain action, all three need to be of a certain type. In order to find out the type of the product, I need to make a service call and wait for a response.
What I would like to do is wait for all three responses (maybe with a timeout in case something goes wrong) and when all the info is gathered, decide whether or not to enable the possible action.
I used to solve this by having some counter or reset events to keep track of the finished events but I would like to see if I can use Rx to do it in a cleaner way.
As I am not too familiar with Rx yet, I am looking for some tips/pointers. I understand I can use
Observable.FromEventPattern
for the events I am waiting on. I subscribe and wait for the response and handle it. I am just not clear on how to combine the multiple events.
The combinator you are looking for is CombineLatest
Say you've got a class like this:
public class Foo
{
public delegate void FooEventHandler(object sender, EventArgs args);
public event FooEventHandler FirstEvent = delegate {};
public event FooEventHandler SecondEvent = delegate {};
public event FooEventHandler ThirdEvent = delegate {};
public void DoIt()
{
FireOne();
FireTwo();
FireThree();
}
public void FireOne()
{
Console.WriteLine("Firing event 1...");
Thread.Sleep(1000);
FirstEvent(this, new EventArgs());
}
public void FireTwo()
{
Console.WriteLine("Firing event 2...");
Thread.Sleep(1000);
SecondEvent(this, new EventArgs());
}
public void FireThree()
{
Console.WriteLine("Firing event 3...");
Thread.Sleep(1000);
ThirdEvent(this, new EventArgs());
}
}
First you'd want to "convert" those events to Observable:
var foo = new Foo();
var firstWatcher = Observable.FromEventPattern(foo, "FirstEvent");
var secondWatcher = Observable.FromEventPattern(foo, "SecondEvent");
var thirdWatcher = Observable.FromEventPattern(foo, "ThirdEvent");
Now you'll want the "Only fire when all these have fired" selector, which is CombineLatest:
var allDone = Observable.CombineLatest(firstWatcher, secondWatcher, thirdWatcher);
And to test it out:
using(allDone.Subscribe(_ => Console.WriteLine("Boop! You sunk my battleship!")))
{
foo.DoIt();
}
Alternative "test harness":
var foo = new Foo();
var firstWatcher = Observable.FromEventPattern(foo, "FirstEvent");
var secondWatcher = Observable.FromEventPattern(foo, "SecondEvent");
var thirdWatcher = Observable.FromEventPattern(foo, "ThirdEvent");
var allDone = Observable.CombineLatest(firstWatcher, secondWatcher, thirdWatcher);
// keep a handle on the subscription
IDisposable subscription = null;
// to prevent premature exiting...
var blocker = new ManualResetEvent(false);
// explicit subscribe
subscription = allDone.Subscribe(
whoCares =>
{
Console.WriteLine("BOOM! We're done!");
// always clean up after yourself
if(subscription != null)
{
subscription.Dispose();
}
// it's ok, we can quit now
blocker.Set();
});
foo.DoIt();
// Wait until it's clear to go ahead...
blocker.WaitOne();

How to execute method calls of a custom class in a separate thread?

I have an UI, a custom class, and a thread. I want to run the custom class completely in a separate thread. Is there a clean way of doing this?
For example. On the MainForm below, when UI calls _threadOneClass.Sleep, I need the UI to go to the spawned ThreadOne and invoke the Sleep method in ThreadOne, not in the main thread.
Basically, all method calls in MyClass need to be executed in ThreadOne, not in main thread. It is like, the MyClass runs on its own "process", while still visible to be called from MainForm.
The MainForm has 3 buttons, and 1 textbox for logging.
I was thinking of deriving the Thread class, but it is sealed. So deriving is definitely a wrong way per Microsoft.
Help dear experts?
Here is the output (MainThread ID=10, ThreadOne ID=11)
MyClass instantiated
Starting ThreadOne
11-Run.start
Sleeping ThreadOne
10-Run.sleep for 3000 'Need this to run on ThreadID 11
10-Run.woke up 'Need this to run on ThreadID 11
Stopping ThreadOne
11-Run.done
Here is how the code look like.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private Thread _threadOneThread;
private MyClass _threadOneClass;
private void btnThreadOneCreate_Click(object sender, EventArgs e)
{
_threadOneClass = new MyClass(this);
_threadOneThread = new Thread(new ThreadStart(_threadOneClass.Run));
_threadOneThread.Start();
}
private void btnThreadOneStop_Click(object sender, EventArgs e)
{
_threadOneClass.IsRunning = false;
}
private void btnThreadOneSleep_Click(object sender, EventArgs e)
{
_threadOneClass.Sleep(3000);
}
public void Log(string txt)
{
MainForm.SetText(txtLog, txt);
}
internal static void SetText(Control ctl, string val)
{
if (ctl.InvokeRequired)
ctl.Invoke((MethodInvoker)delegate() { ctl.Text += Environment.NewLine + val; });
else
ctl.Text += Environment.NewLine + val;
}
}
class MyClass
{
public MyClass(MainForm frm)
{
_mainForm = frm;
}
private MainForm _mainForm;
public bool IsRunning = true;
public void Run()
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.start");
while (IsRunning) { }
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.done");
}
public void Sleep(int milliseconds)
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.sleep for " + milliseconds.ToString());
Thread.Sleep(milliseconds);
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.woke up");
}
}
Threads allow you to run heavy operations while you continue doing other things. In the case of user interfaces (your scenario), asynchronous behavior is almost always necessary as blocking the UI thread will cause to be unresponsive to the user and just isn't an option.
Luckily, the folks at Microsoft has made it extremely easy to write the same code, but in an asynchronous manner. I usually use Tasks because I like the control you get over the operation as well as the ContinueWith() lets you control what you do with the result should you need to propagate data back to the calling thread. If you prefer to use threads, ThreadPool.QueueUserWorkItem is just as easy.
Any operation you do not want to block the UI thread wrap it like this,
Task.Factory.StartNew(() => Object.PerformOperation());
or
ThreadPool.QueueUserWorkItem(new WaitCallback((x) => Object.PeroformOperation()));
I find this allows me to write the same exact code, but without blocking the UI thread. If you have several statements to execute you can use a block as well.
Task.Factory.StartNew(() =>
{
// do something
// do more stuff
// done
}).ContinueWith((completedTask) =>
{
// if you were computing a value with the task
// you can now do something with it
// this is like a callback method, but defined inline
// use ui's dispatcher if you need to interact with ui compontents
UI.Label.Dispatcher.Invoke(new Action(() =>
UI.Item.Label.Text = completedTask.Result;
}
The upcoming async features that are being released in the next .net version actually streamline this even more! But since it uses tasks you will still want to get comfortable with using them.
// this will begin the operation, then return control back to the ui so it does not hang.
var result = await Object.PerformLongTask();
// once the long task is completed then it continues and you can use the result
UI.Item.Label = result;
To give a real example, here is some code from an FTP client I wrote which has has a WPF front end. When the start button is clicked the ftp transfer is launched in it's own task, then a while loop which updates the interface every half a second is launched in a task, so neither interferes with the interface thread. Again it's the same code, just wrapped in lambada's.
private void btnStart_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
ftp.Mirror(#"C:\LocalFolder", "/RemoteFolder", 10));
Task.Factory.StartNew(() =>
{
while (true)
{
lbPercentSuccess.Dispatcher.Invoke(new Action(() =>
{
lbPercentSuccess.Content = ftp.FtpProgress.SuccessPercentage;
lbPercentError.Content = ftp.FtpProgress.ErrorPercentage;
lbPercentTotal.Content = ftp.FtpProgress.TotalPercentage;
lbDuration.Content = ftp.FtpProgress.Duration;
}));
Thread.Sleep(500);
}
});
}
This is not possible to my knowledge. You can only run and invoke individual methods or queue them on separate threads when need be. Setting an actual object on a separate thread defeats your purpose. This is because you only going to harness the benefits of multithreading when invoking a method on a separate thread not an object.
then reassign the del to MethodTwo... and so on. This is made easier if you conform to a method signature.
Possible solution:
Thread threadTest = new Thread(new ThreadStart(MethodOne));
threadTest = new Thread(new ThreadStart(MethodTwo));
threadTest.Start();
Or
Action del = TestClass.MethodOne;
IAsyncResult result = del.BeginInvoke(null, null);
Func<int,int> del = TestClass.MethodOne;
IAsyncResult result = del.BeginInvoke(11,null, null);
int value = del.EndInvoke(result);
It's not simple, but have a look at this. It's a nice explination of how to use cross thread communication.
http://www.codeproject.com/KB/cs/delegatequeue.aspx
So far, this is what I found (from iPhone development). The Run loop acts like a spine that invokes various methods. It is implemented like the following:
A more elegant solution is welcomed.
class MyClass
{
public MyClass(MainForm frm)
{
_mainForm = frm;
}
private MainForm _mainForm;
public bool IsRunning = true;
public void Run()
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.start");
while (IsRunning)
{
if (_runSleepMilliSeconds != null)
{
_Sleep(_runSleepMilliSeconds ?? 3000);
_runSleepMilliSeconds = null;
}
}
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.done");
}
private int? _runSleepMilliSeconds = null;
public void Sleep(int milliseconds)
{
_runSleepMilliSeconds = milliseconds;
}
private void _Sleep(int milliseconds)
{
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.sleep for " + milliseconds.ToString());
Thread.Sleep(milliseconds);
_mainForm.Log(Thread.CurrentThread.ManagedThreadId.ToString() + "-Run.woke up");
}
}

How to ensure run of a thread exactly after end of running of a specifc number of other threads?

I have a class in C# like this:
public MyClass
{
public void Start() { ... }
public void Method_01() { ... }
public void Method_02() { ... }
public void Method_03() { ... }
}
When I call the "Start()" method, an external class start to work and will create many parallel threads that those parallel threads call the "Method_01()" and "Method_02()" form above class. after end of working of the external class, the "Method_03()" will be run in another parallel thread.
Threads of "Method_01()" or "Method_02()" are created before creation of thread of Method_03(), but there is no guaranty to end before start of thread of "Method_03()". I mean the "Method_01()" or the "Method_02()" will lost their CPU turn and the "Method_03" will get the CPU turn and will end completely.
In the "Start()" method I know the total number of threads that are supposed to create and run "Method_01" and "Method_02()". The question is that I'm searching for a way using semaphore or mutex to ensure that the first statement of "Method_03()" will be run exactly after end of all threads which are running "Method_01()" or "Method_02()".
Three options that come to mind are:
Keep an array of Thread instances and call Join on all of them from Method_03.
Use a single CountdownEvent instance and call Wait from Method_03.
Allocate one ManualResetEvent for each Method_01 or Method_02 call and call WaitHandle.WaitAll on all of them from Method_03 (this is not very scalable).
I prefer to use a CountdownEvent because it is a lot more versatile and is still super scalable.
public class MyClass
{
private CountdownEvent m_Finished = new CountdownEvent(0);
public void Start()
{
m_Finished.AddCount(); // Increment to indicate that this thread is active.
for (int i = 0; i < NUMBER_OF_THREADS; i++)
{
m_Finished.AddCount(); // Increment to indicate another active thread.
new Thread(Method_01).Start();
}
for (int i = 0; i < NUMBER_OF_THREADS; i++)
{
m_Finished.AddCount(); // Increment to indicate another active thread.
new Thread(Method_02).Start();
}
new Thread(Method_03).Start();
m_Finished.Signal(); // Signal to indicate that this thread is done.
}
private void Method_01()
{
try
{
// Add your logic here.
}
finally
{
m_Finished.Signal(); // Signal to indicate that this thread is done.
}
}
private void Method_02()
{
try
{
// Add your logic here.
}
finally
{
m_Finished.Signal(); // Signal to indicate that this thread is done.
}
}
private void Method_03()
{
m_Finished.Wait(); // Wait for all signals.
// Add your logic here.
}
}
This appears to be a perfect job for Tasks. Below I assume that Method01 and Method02 are allowed to run concurrently with no specific order of invocation or finishing (with no guarantee, just typed in out of memory without testing):
int cTaskNumber01 = 3, cTaskNumber02 = 5;
Task tMaster = new Task(() => {
for (int tI = 0; tI < cTaskNumber01; ++tI)
new Task(Method01, TaskCreationOptions.AttachedToParent).Start();
for (int tI = 0; tI < cTaskNumber02; ++tI)
new Task(Method02, TaskCreationOptions.AttachedToParent).Start();
});
// after master and its children are finished, Method03 is invoked
tMaster.ContinueWith(Method03);
// let it go...
tMaster.Start();
What it sounds like you need to do is to create a ManualResetEvent (initialized to unset) or some other WatHandle for each of Method_01 and Method_02, and then have Method_03's thread use WaitHandle.WaitAll on the set of handles.
Alternatively, if you can reference the Thread variables used to run Method_01 and Method_02, you could have Method_03's thread use Thread.Join to wait on both. This assumes however that those threads are actually terminated when they complete execution of Method_01 and Method_02- if they are not, you need to resort to the first solution I mention.
Why not use a static variable static volatile int threadRuns, which is initialized with the number threads Method_01 and Method_02 will be run.
Then you modify each of those two methods to decrement threadRuns just before exit:
...
lock(typeof(MyClass)) {
--threadRuns;
}
...
Then in the beginning of Method_03 you wait until threadRuns is 0 and then proceed:
while(threadRuns != 0)
Thread.Sleep(10);
Did I understand the quesiton correctly?
There is actually an alternative in the Barrier class that is new in .Net 4.0. This simplifies the how you can do the signalling across multiple threads.
You could do something like the following code, but this is mostly useful when synchronizing different processing threads.
public class Synchro
{
private Barrier _barrier;
public void Start(int numThreads)
{
_barrier = new Barrier((numThreads * 2)+1);
for (int i = 0; i < numThreads; i++)
{
new Thread(Method1).Start();
new Thread(Method2).Start();
}
new Thread(Method3).Start();
}
public void Method1()
{
//Do some work
_barrier.SignalAndWait();
}
public void Method2()
{
//Do some other work.
_barrier.SignalAndWait();
}
public void Method3()
{
_barrier.SignalAndWait();
//Do some other cleanup work.
}
}
I would also like to suggest that since your problem statement was quite abstract, that often actual problems that are solved using countdownevent are now better solved using the new Parallel or PLINQ capabilities. If you were actually processing a collection or something in your code, you might have something like the following.
public class Synchro
{
public void Start(List<someClass> collection)
{
new Thread(()=>Method3(collection));
}
public void Method1(someClass)
{
//Do some work.
}
public void Method2(someClass)
{
//Do some other work.
}
public void Method3(List<someClass> collection)
{
//Do your work on each item in Parrallel threads.
Parallel.ForEach(collection, x => { Method1(x); Method2(x); });
//Do some work on the total collection like sorting or whatever.
}
}

Categories