How to manage thread blocking and unblocking with asynchronous events? - c#

Background
I am currently recreating functionality of something with a GUI that works in and, but through a terminal interface. So the error is not on the other end with the events triggering, because it works in original GUI form.
I run a task composed of subtasks on multiple machines.
I subscribe to events which trigger when progress is made and print out a descriptive message.
A message is to be printed out for each X subtasks for all Y machines.
Asynchronous multithreading operation then occurs.
I would like to print out a message for each subtask for each machine being resolved only once.
I track completion of the subtasks, and keep a 2D boolean array where rows is machines and columns subtasks.
Problem
When debugging I can see that the event handler methods below are being entered. The print statement in numOfSubtasksFoundEventHandler is run, but before I reach to set the AutoReset event multiple BigTask events are triggered, blocked at the .WaitOne.
However despite the fact that numOfSubtasksFound.Set() is run later, nothing else is printed nor does the program finish execution. Nothing gets past the numOfSubtasksFound.WaitOne s.
If I take out the numOfSubtasksFound.WaitOne in the BigTaskHandler method I receive similar behavior but a few messages stating the BigTask completes and then the program stalls somewhere else.
What is the best way to manage the blocking and unblocking here or is there a small fix?
Goal
What I need is a way to block the operation of the subtask event handler method until numOfSubtasksFoundEventHandler has run once. I only need numOfSubTasksFoundEventHandler to run once only.
Currently the subtask event handler is not being unblocked properly. The switch case code is never executed after numOfSubtasksFound.Set(); is run.
//MAIN
bool[] machinesDoneTasks = new bool[numOfMachines];
bool[][] machinesDoneSubtasks = new bool[numOfMachines][];
try
{
//thread/task blocking
numOfSubtasksFound = new AutoResetEvent(false);
AllSubTasksDone = new AutoResetEvent(false);
AllBigTasksDone = new AutoResetEvent(false);
//Subscribe to events to get number of subtasks and print useful information as tasks progress
numOfSubtasksFoundEvent += numOfSubtasksFoundEventHandler;
SubTaskProgEvent += SubTaskEventProgHandler; //prog stands for progress
BigTaskProgEvent += BigTaskProgEventHandler;
RunAllTasksOnAllMachines();//this will trigger the events above
//Don't exit program until those descriptive messages have been printed
numOfSubtasksFound.WaitOne();
AllSubTasksDone.WaitOne();
//SubTaskProgEvent -= SubTaskProgEventHandler;
AllBigTasksDone.WaitOne();
//BigTaskProgEvent -= BigTaskProgEventHandler;
}
catch (Exception e)
{
//print exceptions
}
//END MAIN
Below is not necessarily the 1st event to be triggered.
internal void numOfSubtasksFoundEventHandler(object sender, EventArgs e)
{
//get number of subtasks from args after checking for nulls, empty arrays
for (int i = 0; i < numOfSubtasks; i++)
machinesDoneSubtasks[i] = new bool[numOfSubtasks];
Console.WriteLine("number of subtasks found");
numOfSubtasksFoundEvent -= numOfSubtasksFoundEventHandler;//don't subscribe to event where we get this from anymore
if (numOfSubtasksFound != null)
numOfSubtasksFound.Set(); //stop blocking
}
Subtask events do not necessarily get processed before big task events.
internal void SubtaskEventProgHandler(object sender, EventArgs e)
{
//null, empty checks on args
//Wait until we know how many subtasks there are and the 2D boolean array is fully built
numOfSubtasksFound.WaitOne();
switch (e.WhatHappened)
{
Case.TaskComplete:
Console.Write(e.Machine + " is done subtask " + e.subTask);
//logic to determine machine and subtask
machinesDoneSubtasks[machine][Subtask] = true;
if (AllSubTasksDone != null && machinesDoneSubtasks.OfType<bool>().All(x => x))
AllSubTasksDone.Set(); //stop blocking when 2D array is all true
break;
//other cases, different prints, but same idea
}
}
BigTask progress events occur at the beginning middle and end of processing. I only print out the details of the Cases I want.
internal void BigTaskProgEventHandler(object sender, EventArgs e)
{
//Wait until we know how many subtasks there are and the 2D boolean array is fully built before printing
numOfSubtasksFound.WaitOne();
//null, empty exception checks
switch (e.WhatHappened)
{
Case.TaskComplete:
Console.Write(e.Machine + " is done task " + e.subTask);
//logic to determine machine
machinesDoneTasks[machine] = true;
if (AllBigTasksDone != null && machinesDoneTasks.All(x => x))
AllBigTasksDone.Set();
break;
}
//other cases, different prints, but same idea
}

An example of async/await model.
A number of tasks run on each machine and compute a value.
When all tasks are done the values are displayed on the console.
static void Main(string[] args)
{
var service = new DispatchTasksOnMachinesService(8, 3);
service.DispatchTasks();
Console.Read();
}
class DispatchTasksOnMachinesService
{
int numOfMachines;
int tasksPerMachine;
[ThreadStatic]
private Random random = new Random();
public DispatchTasksOnMachinesService(int numOfMachines, int tasksPerMachine)
{
this.numOfMachines = numOfMachines;
this.tasksPerMachine = tasksPerMachine;
}
public async void DispatchTasks()
{
var tasks = new List<Task<Tuple<Guid, Machine, int>>>();
for (int i = 0; i < this.numOfMachines; i++)
{
var j = i;
for (int k = 0; k < this.tasksPerMachine; k++)
{
var task = Task.Run(() => Foo(Guid.NewGuid(), new Machine("machine" + j)));
tasks.Add(task);
}
}
var results = await Task.WhenAll<Tuple<Guid, Machine, int>>(tasks);
foreach (var result in results)
{
Console.WriteLine($"Task {result.Item1} on {result.Item2} yielded result {result.Item3}");
}
}
private Tuple<Guid, Machine, int> Foo(Guid taskId, Machine machine)
{
Thread.Sleep(TimeSpan.FromSeconds(random.Next(1,5)));
Console.WriteLine($"Task {taskId} has completed on {machine}");
return new Tuple<Guid, Machine, int>(taskId, machine, random.Next(500, 2000));
}
}
class Machine
{
public string Name { get; private set; }
public Machine(string name)
{
this.Name = name;
}
public override string ToString()
{
return this.Name;
}
}

My issue was that after the 1st event was triggered, other subtask event handler event would call .WaitOne which would block. This could happen after the number of subtasks is discovered. The issue then was the .Set would only be called once, and it would never be unblocked.
So using a boolean flag to be set when the number of subtasks is discovered, and locking the sub task event handler was the way to go.

Related

Two Thread tasks in Winforms Continuously Checking Back

I am currently trying to keep a counter on C# on a local file folder for new files that are created.
I have two sub directories to CD and LP that I have to keep checking. With counters that makes sure that the count of folders made have not exceeded the count set by the user.
public static int LPmax { get; set; }
public static int CDmax { get; set; }
public static int LPcounter2 { get; set; }
public static int CDcounter2 { get; set; }
public static int LPCreated;
public static int CDCreated;
public static int oldLPCreated;
public static int oldCDCreated;
FileSystemWatcher CDdirWatcher = new FileSystemWatcher();
FileSystemWatcher LPdirWatcher = new FileSystemWatcher();
//watch method should run in the background as checker
public void watch()
{
CDdirWatcher.Path = #"C:\Data\LotData\CD";
CDdirWatcher.Filter = "EM*";
CDdirWatcher.NotifyFilter = NotifyFilters.DirectoryName | NotifyFilters.LastWrite;
CDdirWatcher.EnableRaisingEvents = true;
CDdirWatcher.Created += CDdirWatcher_Created;
LPdirWatcher.Path = #"C:\Data\LotData\LP";
LPdirWatcher.Filter = "EM*";
LPdirWatcher.NotifyFilter = NotifyFilters.DirectoryName;
LPdirWatcher.EnableRaisingEvents = true;
LPdirWatcher.Created += LPdirWatcher_Created;
Thread.Sleep(10);
}
private static void CDdirWatcher_Created(object sender, FileSystemEventArgs e)
{
CDCreated += 1;
}
private static void LPdirWatcher_Created(object sender, FileSystemEventArgs e)
{
LPCreated += 1;
}
The above method works fine, and the criteria is that it has to be less count then the one set
public void checker()
{
if(CDCreated>CDmax)
{
popupbx();
}
if(LPCreated>LPmax)
{
popupbx();
}
}
The problem is my main method where I have two threads which need to continuously check the two criteria to see if the counter has been exceeded.
public Form1()
{
InitializeComponent();
//Implementing Threads asynchronously
Thread oThreadone = new Thread(() =>
{
//Do what u wanna……
watch();
});
Thread oThreadtwo = new Thread(() =>
{
//Do what u wanna……
checker();
});
//Calling thread workers
oThreadone.Start();
oThreadone.IsBackground = true;
oThreadtwo.Start();
oThreadtwo.IsBackground = true;
}
Mkdir fires the counters in debug mode, but thread two doesn't check for the counters after they fire.
The first major thing wrong with your code is that neither of threads you create are needed, nor do they do what you want. Specifically, the FileSystemWatcher object itself is already asynchronous, so you can create it in the main thread. In fact, you should, because there you could set FileSystemWatcher.SynchronizingObject to the current form instance so that it will raise its events in that object's synchronization context. I.e. your event handlers will be executed in the main thread, which is what you want.
So the first method, watch(), rather than being executed in a thread, just call it directly.
Which brings me to the second method, checker(). Your method for the thread doesn't loop, so it will execute the two tests, and then promptly exit. That's the end of that thread. It won't stay around long enough to monitor the counts as they are updated.
You could fix it by looping in the checker() method, so that it never exits. But then you run into problems of excessive CPU usage. Which you'll fix by adding sleep statements. Which then you're wasting a thread most of the time. Which you could fix by using async/await (e.g. await Task.Delay()). Except that would just unnecessarily complicate the code.
Instead, you should just perform each check after each count is updated. In theory, you could just display the message immediately. But that will block the event handler subscribed to FileSystemWatcher, possibly delaying additional reports. So you may instead prefer to use Control.BeginInvoke() to defer display of the message until after the event handler has returned.
So, taking all that into account, your code might instead look more like this:
public Form1()
{
InitializeComponent();
watch();
}
private void CDdirWatcher_Created(object sender, FileSystemEventArgs e)
{
CDCreated += 1;
if (CDCreated > CDmax)
{
BeginInvoke((MethodInvoker)popupbx);
}
}
private static void LPdirWatcher_Created(object sender, FileSystemEventArgs e)
{
LPCreated += 1;
if (LPCreated > LPmax)
{
BeginInvoke((MethodInvoker)popupbx);
}
}
You can remove the checker() method altogether. The watch() method can remain as it is, though I would change the order of subscribing to the Created event and the assignment of EnableRaisingEvents. I.e. don't enable raising events until you've already subscribed to the event. The FileSystemWatcher is unreliable enough as it is, without you giving it a chance to raise an event before you're ready to observe it. :)
This is based on your current implementation. Note though that if files keep getting created, the message will be displayed over and over. If they are created fast enough, new messages will be displayed before the user can dismiss the previously-displayed one(s). You may prefer to modify your code to prevent this. E.g. unsubscribe from the event after you've already exceeded the max count, or at least temporarily inhibit the display of the message while one such message is already being displayed. Exactly what to do is up to you, and beyond the scope of your question and thus the scope of this answer.

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();
}
}

Backgroundworker cancel the worker

I'm facing some troubles when trying to cancel the Backgroundworker.
I've read dozens os similiar topics such as How to stop BackgroundWorker correctly, How to wait correctly until BackgroundWorker completes? but I'm not reaching anywhere.
What's happening is that I have a C# application that uses a PHP WebService to send info to a MySQL database. If the user, for some reason, clicks (in the form) on the "back" or "stop" button, this is the code that is fired:
BgWorkDocuments.CancelAsync();
BgWorkArticles.CancelAsync();
I do understand that the request is Asynchronous, therefore the cancelation might take 1 or 2 seconds, but it should stop..and that doesn't happen at all. Even after clicked "back" (the current form is closed and a new one is opened) the backgroundworker continues to work, because I keep seeing data being inserted into MySQL.
foreach (string[] conn in lines)
{
string connectionString = conn[0];
FbConnection fbConn = new FbConnection(connectionString);
fbConn.Open();
getDocuments(fbConn);
// Checks if one of the backgrounds is currently busy
// If it is, then keep pushing the events until stop.
// Only after everything is completed is when it's allowed to close the connection.
//
// OBS: Might the problem be here?
while (BgWorkDocuments.IsBusy == true || BgWorkArticles.IsBusy == true)
{
Application.DoEvents();
}
fbConn.Close();
}
The above code is needed because I might have multiple databases, that's why I have the loop.
private void getDocuments(FbConnection fbConn)
{
BgWorkDocuments.RunWorkerAsync();
BgWorkDocuments.DoWork += (object _sender, DoWorkEventArgs args) =>
{
DataTable dt = getNewDocuments(fbConn);
for (int i = 0; i <= dt.Rows.Count - 1; i++)
{
// Checks if the user has stopped the background worker
if (BgWorkDocuments.CancellationPending == false)
{
// Continue doing what has to do..
sendDocumentsToMySQL((int)dt.Rows[i]["ID"]);
}
}
// After the previous loop is completed,
// start the new backgroundworker
getArticles(fbConn);
};
}
private void getArticles(FbConnection fbConn)
{
BgWorkArticles.RunWorkerAsync();
BgWorkArticles.DoWork += (object _sender, DoWorkEventArgs args) =>
{
DataTable dt = getNewArticles(fbConn);
for (int i = 0; i <= dt.Rows.Count - 1; i++)
{
// Checks if the user has stopped the background worker
if (BgWorkArticles.CancellationPending == false)
{
// Continue doing what has to do..
sendArticlesToMySQL((int)dt.Rows[i]["ID"]);
}
}
};
}
I agree with the comments expressing surprise that the code even works, due to the apparent ordering problem of the call to RunWorkerAsync() vs when you actually subscribe to the DoWork event. Additionally, your use of DoEvents() is unwarranted and should be removed (as is the case with any use of DoEvents()).
I also note that your workers don't actually exit when you try to cancel them. You just skip the processing, but continue to loop on the rows. Without seeing the rest of the code, it's impossible to know what's going on, but it's possible that after you cancel, the CancellationPending property gets reset to false, allowing the loops to start doing things again.
The lack of a complete code example is a real impediment to understanding the full detail of what's going on.
That said, IMHO this does not seem to be a case where you actually need BackgroundWorker at all, not with the new async/await feature in C#. Given that network I/O is involved, my guess is that each call to sendDocumentsToMySQL() and sendArticlesToMySQL() can be executed individually in the thread pool without too much overhead (or may even be able to be written as async I/O methods…again, lacking detail as to their specific implementation prevents any specific advise in that respect). Given that, your code could probably be rewritten so that it looks more like this:
private CancellationTokenSource _cancelSource;
private void stopButton_Click(object sender, EventArgs e)
{
if (_cancelSource != null)
{
_cancelSource.Cancel();
}
}
private async void startButton_Click(object sender, EventArgs e)
{
using (CancellationTokenSource cancelSource = new CancellationTokenSource)
{
_cancelSource = cancelSource;
try
{
foreach (string[] conn in lines)
{
string connectionString = conn[0];
FbConnection fbConn = new FbConnection(connectionString);
fbConn.Open();
try
{
await getDocuments(fbConn, cancelSource.Token);
await getArticles(fbConn, cancelSource.Token);
}
catch (OperationCanceledException)
{
return;
}
finally
{
fbConn.Close();
}
}
}
finally
{
_cancelSource = null;
}
}
}
private async Task getDocuments(FbConnection fbConn, CancellationToken cancelToken)
{
DataTable dt = await Task.Run(() => getNewDocuments(fbConn));
for (int i = 0; i <= dt.Rows.Count - 1; i++)
{
cancelToken.ThrowIfCancellationRequested();
await Task.Run(() => sendDocumentsToMySQL((int)dt.Rows[i]["ID"]));
}
}
private async Task getArticles(FbConnection fbConn, CancellationToken cancelToken)
{
DataTable dt = await Task.Run(() => getNewArticles(fbConn));
for (int i = 0; i <= dt.Rows.Count - 1; i++)
{
cancelToken.ThrowIfCancellationRequested();
await Task.Run(() => sendArticlesToMySQL((int)dt.Rows[i]["ID"]));
}
}

C# BackgroundWorker

I have a button that on click event I get some information from the network.
When I get information I parse it and add items to ListBox. All is fine, but when I do a fast double-click on button, it seems that two background workers are running and after finishing all work, items in the list are dublicated.
I want to do so that if you click button and the proccess of getting information is in work, this thread is stopping and only after first work is completed the second one is beginning.
Yes, I know about AutoResetEvent, but when I used it it helped me only one time and never more. I can't implement this situation and hope that you will help me!
Now I even try to make easier but no success :( : I added a flag field(RefreshDialogs)(default false), when the user clicks on button, if flag is true(it means that work is doing), nothing is doing, but when flag field is set to false, all is fine and we start a new proccess.
When Backgroundwork completes, I change field flag to false(it means that user can run a new proccess).
private void Message_Refresh_Click(object sender, EventArgs e)
{
if (!RefreshDialogs)
{
RefreshDialogs = true;
if (threadBackgroundDialogs.WorkerSupportsCancellation)
{
threadBackgroundDialogs.CancelAsync();
}
if (!threadBackgroundDialogs.IsBusy)
{
downloadedDialogs = 0;
threadBackgroundDialogs = new BackgroundWorker();
threadBackgroundDialogs.WorkerSupportsCancellation = true;
threadBackgroundDialogs.DoWork += LoadDialogs;
threadBackgroundDialogs.RunWorkerCompleted += ProcessCompleted;
threadBackgroundDialogs.RunWorkerAsync();
}
}
}
void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
{
RefreshDialogs = false;
}
So you want to keep the second process running while the first works, but they shouldn't disturb each other? And after the first one finishes the second one continues?
Crude way: While loop:
if (!RefreshDialogs)
{
RefreshDialogs = true;
this becomes:
while(RefreshDialogs)
{
}
RefreshDialogs = true;
After you set it false the second process wwill jump out of the while. (Note this is extremly inefficent since both processes will be running all the time, i'm pretty sure the second one will block the first one, but with multitasking now it shouldn't, if it block use a Dispatcher.Thread)
Elegant way: Use A Semaphore
http://msdn.microsoft.com/de-de/library/system.threading.semaphore%28v=vs.80%29.aspx
If you find it impossible to have both processes running at the same time, or want another way:
Add an Array/List/int and when the second process notices there is the first process running, like with your bool, increase your Added variable, and at the end of the process, restart the new process and decrese the variable:
int number;
if (!RefreshDialogs)
{
RefreshDialogs = true;
your code;
if(number > 0)
{
number--;
restart process
}
}
else
{
number++;
}
I have to admit, i like my last proposal the most, since its highly efficent.
Make your thread blocking. That is easy;
lock(someSharedGlobalObject)
{
Do Work, Exit early if cancelled
}
This way other threads will wait until the first thread releases the lock. They will never execute simultaneously and silently wait until they can continue.
As for other options; why not disable the button when clicked and re-enable it when the backgroundworker completes. Only problem is this does not allow for cancelling the current thread. The user has to wait for it to finish. It does make any concurrency go away very easily.
How about this approach?
Create a request queue or counter which will be incremented on every button click. Every time that count is > 0. Start the background worker. When the information comes, decrement the count and check for 0. If its still > 0 restart the worker. In that your request handler becomes sequential.
In this approach you may face the problem of continuous reference of the count by two threads, for that you may use a lock unlock condition.
I hav followed this approach for my app and it works well, hope it does the same for you.
I'm not an Windows Phone expert, but as I see it has support for TPL, so following code would read nicely:
private object syncRoot =new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
latestTask = Task.Factory.StartNew(action);
else
latestTask = latestTask.ContinueWith(tsk => action());
}
}
Use can use semaphores
class TheClass
{
static SemaphoreSlim _sem = new SemaphoreSlim (3);
static void Main()
{
for (int i = 1; i <= 5; i++)
new Thread (Enter).Start (i);
}
static void Enter (object name)
{
Console.WriteLine (name + " wants to enter");
_sem.Wait();
Console.WriteLine (name + " has entered!");
Thread.Sleep (1000 * (int) name );
Console.WriteLine (name + " is leaving");
_sem.Release(); }
}
}
I found the solution and thanks to #Giedrius. Flag RefreshingDialogs is set to true only when proccess is at the end, when I added items to Listbox. The reason why I'am using this flag is that state of process changes to complete when the asynchronous operation of getting content from network(HttpWebRequest, method BeginGetRequestStream) begins, but after network operaion is complete I need to make UI operations and not only them(parse content and add it to Listbox)My solution is:
private object syncRoot = new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
{
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
else if(latestTask.IsCompleted && !RefreshingDialogs)
{
RefreshingDialogs = true;
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
}
}
private void Message_Refresh_Click(object sender, EventArgs e)
{
Action ac = new Action(LoadDialogs2);
EnqueueAction(ac);
}

Properly notifying all listeners of a system wide named manual reset event and then immediately resetting it

I have a system-wide manual reset event that I create by doing the following:
EventWaitHandle notifyEvent = new EventWaitHandle(false, EventResetMode.ManualReset, notifyEventName, out createdEvent);
Several processes create this event (e.g. it is shared amongst them). It is used for notifying when something gets updated.
I'd like to be able to set this event so that all of processes waiting on it are signaled and then immediately reset it so that subsequent Waits on the event are blocked.
If I do a
notifyEvent.Set();
notifyEvent.Reset();
It will sometimes notify all listening processes.
If I do a
notifyEvent.Set();
Thread.Sleep(0);
notifyEvent.Reset();
More processes get notified (I assumed this would happen since the scheduler has a chance to run).
And if I do
notifyEvent.Set();
Thread.Sleep(100);
notifyEvent.Reset();
Then everything seems to work out fine and all processes (e.g. ~8) get notified consistently. I don't like the use of a "magic number" for the Sleep call.
Is there a better way to notify all listeners of an OS event in other processes that an event has occurred so that everyone listening to it at the time of notification receive the event signal and then immediately reset the event so that anyone else that goes to listen to the event will block?
UPDATE: A Semaphore doesn't seem to be a good fit here since the number of listeners to the event can vary over time. It is not known in advance how many listeners there will be when an even needs to be notified.
I had the same problem and surprisingly couldn't find any good solution on the web for this loose-coupled / fire and forget / multiple listeners type of event, so here is what I came up with.
Note the solution with the timeout between Set() and Reset() calls has also a race-condition issue (beyond the fact it relies on an arbitrary timeout value): if the publisher gets killed between these calls, then all the listeners will see the event as set forever (unless the publisher gets live again).
So the requirement is:
there is one publisher (although it's not really enforced in the code)
there can be any number of listeners (in the same process or in other processes), between 0 and N (N is fixed once the binaries are compiled).
listeners can come and go as they want without disturbing the publisher
publisher can come and go as it wants without disturbing the listeners
The trick is to use AutoReset events because they don't have race condition issues, but define one per listener. We don't know the number of listeners beforehand but we can fix a maximum number of listeners ('N' described above):
const int MAX_EVENT_LISTENERS = 10;
const string EVENT_NAME = "myEvent_";
Here is the publisher code to raise the event to all potential listeners:
public static void RaiseEvent()
{
for (int i = 0; i < MAX_EVENT_LISTENERS; i++)
{
EventWaitHandle evt;
if (EventWaitHandle.TryOpenExisting(EVENT_NAME + i, out evt))
{
evt.Set();
evt.Dispose();
}
}
}
Here is the listener code to get notified of the event:
...
EventWaitHandle evt = GetEvent();
do
{
bool b = evt.WaitOne();
// event was set!
}
while (true);
....
// create our own event that no other listener has
public static EventWaitHandle GetEvent()
{
for (int i = 0; i < MAX_EVENT_LISTENERS; i++)
{
bool createdNew;
EventWaitHandle evt = new EventWaitHandle(false, EventResetMode.AutoReset, EVENT_NAME + i, out createdNew);
if (createdNew)
return evt;
evt.Dispose();
}
throw new Exception("Increase MAX_EVENT_LISTENERS");
}
You're using the EventWaitHandle class incorrectly. A reset event shouldn't be used to signal multiple threads. Instead, you need to create a reset event for each thread and then when you're ready loop through them all and use Set(). The master thread should not be calling the Reset() method. Each thread should be responsible for closing the gate behind them so to speak.
Here's a basic example:
static class Program
{
static void Main()
{
List<ThreadState> states = new List<ThreadState>();
ThreadState myState;
Thread myThread;
string data = "";
for (int i = 0; i < 4; i++)
{
myThread = new Thread(Work);
myState = new ThreadState();
myState.gate = new EventWaitHandle(false, EventResetMode.ManualReset);
myState.running = true;
myState.index = i + 1;
states.Add(myState);
myThread.Start(myState);
}
Console.WriteLine("Enter q to quit.");
while (data != "q")
{
data = Console.ReadLine();
if (data != "q")
foreach (ThreadState state in states)
state.gate.Set();
}
foreach (ThreadState state in states)
{
state.running = false;
state.gate.Set();
}
Console.WriteLine("Press any key to quit.");
Console.ReadKey();
}
static void Work(Object param)
{
ThreadState state = (ThreadState)param;
while (state.running)
{
Console.WriteLine("Thread #" + state.index + " waiting...");
state.gate.WaitOne();
Console.WriteLine("Thread #" + state.index + " gate opened.");
state.gate.Reset();
Console.WriteLine("Thread #" + state.index + " gate closed.");
}
Console.WriteLine("Thread #" + state.index + " terminating.");
}
private class ThreadState
{
public int index;
public EventWaitHandle gate;
public bool running;
}
}
You are using the wrong synchronization type here. Instead of an event, you should use the Semaphore class, with the number of simultaneous accesses you wish to permit.
You might also want to have two Semaphores, the second one being for the code that fires the event to check (which the code responding to the event would hold locks on) in case you don't want to have two events in quick succession and have one section of code get in on the tails of another event.

Categories