After asking this question, I am wondering if it is possible to wait for an event to be fired, and then get the event data and return part of it. Sort of like this:
private event MyEventHandler event;
public string ReadLine(){ return event.waitForValue().Message; }
...
event("My String");
...elsewhere...
var resp = ReadLine();
Please make sure whatever solution you provide returns the value directly rather than getting it from something else. I'm asking if the method above is available in some way. I know about Auto/ManuelResetEvent, but I don't know that they return the value directly like I did above.
Update: I declared an event using MyEventHandler (which contains a Message field). I have a method in another thread called ReadLine waiting for the event to fire. When the event fires the WaitForValue method (part of the event handling scene) returns the event args, which contains the message. The message is then returned by ReadLine to whatever had called it.
The accepted answer to that question I asked was what I did, but it just doesn't feel quite right. It almost feels like something could happen to the data between the ManuelResetEvent firing and the program retrieving the data and returning it.
Update: The main problem with the Auto/ManualResetEvent is that it is too vulnerable. A thread could wait for the event, and then not give enough time for anyone else to get it before changing it to something else. Is there a way to use locks or something else? Maybe using get and set statements.
If the current method is async then you can use TaskCompletionSource. Create a field that the event handler and the current method can access.
TaskCompletionSource<bool> tcs = null;
private async void Button_Click(object sender, RoutedEventArgs e)
{
tcs = new TaskCompletionSource<bool>();
await tcs.Task;
WelcomeTitle.Text = "Finished work";
}
private void Button_Click2(object sender, RoutedEventArgs e)
{
tcs?.TrySetResult(true);
}
This example uses a form that has a textblock named WelcomeTitle and two buttons. When the first button is clicked it starts the click event but stops at the await line. When the second button is clicked the task is completed and the WelcomeTitle text is updated. If you want to timeout as well then change
await tcs.Task;
to
await Task.WhenAny(tcs.Task, Task.Delay(25000));
if (tcs.Task.IsCompleted)
WelcomeTitle.Text = "Task Completed";
else
WelcomeTitle.Text = "Task Timed Out";
You can use ManualResetEvent. Reset the event before you fire secondary thread and then use the WaitOne() method to block the current thread. You can then have secondary thread set the ManualResetEvent which would cause the main thread to continue. Something like this:
ManualResetEvent oSignalEvent = new ManualResetEvent(false);
void SecondThread(){
//DoStuff
oSignalEvent.Set();
}
void Main(){
//DoStuff
//Call second thread
System.Threading.Thread oSecondThread = new System.Threading.Thread(SecondThread);
oSecondThread.Start();
oSignalEvent.WaitOne(); //This thread will block here until the reset event is sent.
oSignalEvent.Reset();
//Do more stuff
}
A very easy kind of event you can wait for is the ManualResetEvent, and even better, the ManualResetEventSlim.
They have a WaitOne() method that does exactly that. You can wait forever, or set a timeout, or a "cancellation token" which is a way for you to decide to stop waiting for the event (if you want to cancel your work, or your app is asked to exit).
You fire them calling Set().
Here is the doc.
If you're happy to use the Microsoft Reactive Extensions, then this can work nicely:
public class Foo
{
public delegate void MyEventHandler(object source, MessageEventArgs args);
public event MyEventHandler _event;
public string ReadLine()
{
return Observable
.FromEventPattern<MyEventHandler, MessageEventArgs>(
h => this._event += h,
h => this._event -= h)
.Select(ep => ep.EventArgs.Message)
.First();
}
public void SendLine(string message)
{
_event(this, new MessageEventArgs() { Message = message });
}
}
public class MessageEventArgs : EventArgs
{
public string Message;
}
I can use it like this:
var foo = new Foo();
ThreadPoolScheduler.Instance
.Schedule(
TimeSpan.FromSeconds(5.0),
() => foo.SendLine("Bar!"));
var resp = foo.ReadLine();
Console.WriteLine(resp);
I needed to call the SendLine message on a different thread to avoid locking, but this code shows that it works as expected.
Try it : e.Handled = true; It works to prevent KeyEventArgs, for example.
Related
I have an application with a gui and a Rich Text Box where I output what the program is currently doing since data processing can be quite long.
I tried two approaches for that:
1 In the Backgroundworker method I can just call the following code fine:
GlobalVar.backgroundWorkerAppendText = task.Build_CSV_List();
Processchange();
Whereas I cannot use Form1.Processchange(); in the helper class due to the non static context
2 Therefore I tried to create my very first eventhandler.
The Idea was that helper.UpdateConsole() would raise an event
public event EventHandler OnConsoleUpdate;
public void Consoleupdate()
{
OnConsoleUpdate(this, EventArgs.Empty);
}
to which the Backgroundworker listens and then calls Processchange from its context
public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
StandardTasks task = new StandardTasks();
Helper helper = new Helper();
helper.OnConsoleUpdate += Processchange;
task.DoSomeStuffHere()
}
public void Processchange(object sender=null, EventArgs e=null)
{
//MessageBox.Show(GlobalVar.backgroundWorkerAppendText);
GlobalVar.next = false;
backgroundWorker1.ReportProgress(1);
while (GlobalVar.next == false)
{
helper.TimeBreaker(100,"ms");
}
}
Unfortunately this was was not successful. As soon as rising the Event I get the errormessage System.NullReferenceException which -after googling- leads me to the conclusion that there is no listerner attached to the event eventhouh I attached it in the Backgroundworker Do work.
Edit: the OnConsoleUpdate() == null as shown on the screenshot below
event = null
The helper is in another class file "helpers" which might be important for a solution.
i hope you guys can help me out.
Welcome to SO!
A few things immediately jump to mind.
First, let's get the event issue out of the way. You've got the correct approach - you need an event and method to call it, but that method should check if the event is null.
Basically, do this:
public event EventHandler OnConsoleUpdate;
public void ConsoleUpdate()
{
OnConsoleUpdate?.Invoke(this, EventArgs.Empty);
}
The above makes use of ?, a null-condition operator. You can read more about it on this MSDN page.
Second thing... it's unclear what your background worker actually IS. It sounds like it's some kind of custom class you crated? The reason it's important is because .NET actually has a BackgroundWorker class used for running operations... well, in the background. It also has an OnProgressChanged event which you can hook up to which could be used to update the UI (just remember to set the WorkerReportsProgress property to true). And to use the BackgroundWorker mentioned above, you shouldn't need to create any events of your own.
Here's how you can use the standard .NET BackgroundWorker:
System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker();
void StartBackgroundTask()
{
worker.DoWork += worker_DoWork;
//if it's possible to display progress, use this
worker.WorkerReportsProgress = true;
worker.ProgressChanged += worker_ProgressChanged;
//what to do when the method finishes?
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
//start!
worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
//perform any "finalization" operations, like re-enable disabled buttons
//display the result using the data in e.Result
//this code will be running in the UI thread
}
//example of a container class to pass more data in the ReportProgress event
public class ProgressData
{
public string OperationDescription { get; set; }
public int CurrentResult { get; set; }
//feel free to add more stuff here
}
void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
//display the progress using e.ProgressPercentage or e.UserState
//this code will be running in the UI thread
//UserState can be ANYTHING:
//var data = (ProgressData)e.UserState;
}
void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
//this code will NOT be running in the UI thread!
//you should NOT call the UI thread from this method
int result = 1;
//perform calculations
for (var i = 1; i <= 10; i++)
{
worker.ReportProgress(i, new ProgressData(){ OperationDescription = "CustomState passed as second, optional parameter", CurrentResult = result });
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
result *= i;
}
e.Result = result;
}
Now, the thing about the BackgroundWorker class is that it is rather old, and with current .NET versions you can use the async / await keywords to easily handle background operations and UI updates, but this probably is going outside the bounds of this question. That said, the existence of async / await doesn't invalidate the use of BackgroundWorker which is pretty simple in its usage.
There's one more worrisome thing in your code.
public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
StandardTasks task = new StandardTasks(); //<- you create a task
Helper helper = new Helper(); // <- you create a helper
helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper event
task.DoSomeStuffHere(); // <- you do stuff with the task... but the task doesn't know about your helper above! Does `StandardTasks` use `Helper`? If so, how?
}
Do note that events, unless made static, aren't global. So hooking up to an event in one instance of a class won't cause another instance of that class to "fire" that event. It seems one way to fix your issues would be to make the StandardTasks class take Helper as one of the constructor parameters, so the code would look like this:
Helper helper = new Helper(); // <- you create a helper
helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper class event to actually do something
StandardTasks task = new StandardTasks(helper); //<- you create a task which will use the helper with the hooked up event above
I am currently experiencing some unexpected/unwanted behavior with an aync method I am trying to use. The async method is RecognizeAsync. I am unabled to await this method since it returns void. What is happening, is that ProcessAudio method will be called first and will seemingly run to completion however the webpage never returns my "Contact" view as it should or errors out. After the method runs to completion, the breakpoints in my handlers start being hit. If I let it play through to completion, no redirect will ever happen- in the network tab in chrome debugger, the "status" will stay marked as pending and just hang there. I believe my issue is being caused by issues with asynchronousity but have been unable to found out what exactly it is.
All help is appreciated.
[HttpPost]
public async Task<ActionResult> ProcessAudio()
{
SpeechRecognitionEngine speechEngine = new SpeechRecognitionEngine();
speechEngine.SetInputToWaveFile(Server.MapPath("~/Content/AudioAssets/speechSample.wav"));
var grammar = new DictationGrammar();
speechEngine.LoadGrammar(grammar);
speechEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(SpeechRecognizedHandler);
speechEngine.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(SpeechHypothesizedHandler);
speechEngine.RecognizeAsync(RecognizeMode.Multiple);
return View("Contact", vm); //first breakpoint hit occurs on this line
//but it doesnt seem to be executed?
}
private void SpeechRecognizedHandler(object sender, EventArgs e)
{
//do some work
//3rd breakpoint is hit here
}
private void SpeechHypothesizedHandler(object sender, EventArgs e)
{
//do some different work
//2nd breakpoint is hit here
}
UPDATE: based on suggestions, I have changed my code to (in ProcessAudio):
using (speechEngine)
{
speechEngine.SetInputToWaveFile(Server.MapPath("~/Content/AudioAssets/speechSample.wav"));
var grammar = new DictationGrammar();
speechEngine.LoadGrammar(grammar);
speechEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(SpeechRecognizedHandler);
speechEngine.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(SpeechHypothesizedHandler);
var tcsRecognized = new TaskCompletionSource<EventArgs>();
speechEngine.RecognizeCompleted += (sender, eventArgs) => tcsRecognized.SetResult(eventArgs);
speechEngine.RecognizeAsync(RecognizeMode.Multiple);
try
{
var eventArgsRecognized = await tcsRecognized.Task;
}
catch(Exception e)
{
throw (e);
}
}
and this is resulting in some wrong behavior:
The return View("Contact",vm) breakpoint will now be hit AFTER the handlers are finished firing however there is still no redirect that ever happens. I am never directed to my Contact page. I just si ton my original page indefinitely just like before.
You're going too early. The speech engine probably hasn't even started by the time you hit the return View line.
You need to wait until the final event is fired from the speech engine. The best approach would be to convert from the event based asynchrony to TAP-based asynchrony.
This can be achieved by using TaskCompletionSource<T>
Let's deal with (what I believe) should be the last event to fire after speechEngine.RecognizeAsync is called, i.e. SpeechRecognized. I'm assuming that this is the event that fires when the final result has been calculated by the speech engine.
So, first:
var tcs = new TaskCompletionSource<EventArgs>();
now lets hook it up to complete when SpeechRecognized is fired, using inline lambda-style method declaration:
speechEngine.SpeechRecognized += (sender, eventArgs) => tcs.SetResult(eventArgs);
(...wait... what happens if no speech was recognized? We'll also need to hook up the SpeechRecognitionRejected event and define a custom Exception subclass for this type of event... here I'll just call it RecognitionFailedException. Now we're trapping all possible outcomes of the recognition process, so we would hope that the TaskCompletionSource would complete in all outcomes.)
speechEngine.SpeechRecognitionRejected += (sender, eventArgs) =>
tcs.SetException(new RecognitionFailedException());
then
speechEngine.RecognizeAsync(RecognizeMode.Multiple);
now, we can await the Task property of our TaskCompletionSource:
try
{
var eventArgs = await tcs.Task;
}
catch(RecognitionFailedException ex)
{
//this would signal that nothing was recognized
}
do some processing on the EventArgs that is the Task's result, and return a viable result back to the client.
In the process of doing this, you are creating IDisposable instances that will need to be properly disposed.
So:
using(SpeechRecognitionEngine speechEngine = new SpeechRecognitionEngine())
{
//use the speechEngine with TaskCompletionSource
//wait until it's finished
try
{
var eventArgs = await tcs.Task;
}
catch(RecognitionFailedException ex)
{
//this would signal that nothing was recognized
}
} //dispose
if anyone is curious- i solved my issue by doing the following:
I changed to using Recognize() instead of RecognizeAsync(..) which lead to InvalidOperationException due to async events trying to be executed at an "invalid time in the pages lifecycle". To overcome this, I wrapped my operations in a thread and joined the thread back to the main thread directly after running it. Code below:
using (speechEngine)
{
var t = new Thread(() =>
{
speechEngine.SetInputToWaveFile(#"C:\AudioAssets\speechSample.wav");
speechEngine.LoadGrammar(dictationGrammar);
speechEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(SpeechRecognizedHandler);
speechEngine.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(SpeechHypothesizedHandler);
speechEngine.Recognize();
});
t.Start();
t.Join();
}
}
I want to write a synchronous test that calls into some asynchronous product tasks.
In the example below, DoSomething() is called by a separate thread, and then it sets the SomethingCompleted event.
In my test code, how do I wait for SomethingCompleted to be set?
public event Action<Result> SomethingCompleted;
public void DoSomething()
{
Something();
this.SomethingCompleted(new Result("Success"));
}
using (var evt = new ManualResetEvent()) {
Action<Result> handler = _ => evt.Set();
SomethingCompleted += handler;
evt.WaitOne();
SomethingCompleted -= handler; //cut object reference to help GC
}
If required you can unsubscribe from the event after the wait has completed. That way the event will not keep the delegate and closure instance alive.
You can extract this into a reusable helper method/extension.
// test case
public void Test()
{
var yourObj = new YourObj();
var done = false;
Result result;
yourObj.SomethingCompleted += (finalResult) => {
result=finalResult;
done=true;
};
yourObj.DoSomething();
while(!done) Thread.Sleep(200);
if(result != theExpectedResult) kaboom();
}
What about subscribing to an event and "polling" the lambda until result comes available? This should work.
You're using the wrong type of event. The event you're using is a callback. In the code you supplied, the delegates attached to the SomethingCompleted event are going to be called on the same thread as DoSomething.
What you want is thread synchronization, using an event like AutoResetEvent or ManualResetEvent, which have nothing to do with the framework/language-level event that you're using. You could do something like this:
void MainThreadProc()
{
// create thread synchronization event
using (var evt = new ManualResetEvent(false))
{
// start background operation
ThreadPool.QueueUserWorkItem(BackgroundThreadProc, evt);
// this line will block until BackgroundThreadProc sets the event
evt.WaitOne();
}
// resume main thread operations here
...
}
void BackgroundThreadProc(object o)
{
// get event from argument
var evt = (ManualResetEvent) o;
// do the deed
...
// set event to signal completion
evt.Set();
}
This is just one of a number of different ways to do this. Alternatives include Parallel LINQ or the Task Parallel Library (both of which are best used with parallel operations, not just a single background operation). If you don't want to block the main thread, look at BackgroundWorker.
How I can aware of a Task finished ?I want a thing like RunWorkerCompleted event in BackGroundWorker.
thanks
You can use ContinueWhenAll, So you will be notified when all processes finished.
Task.Factory.ContinueWhenAll(myTasks, _ => OnAllTasksFinished());
private void OnAllTasksFinished()
{
MessageBox.Show("Finished!");
}
I am calling multithread method from task(in the end)
Pattern multithrea method:
private void SomeEventHandler(object sender, EventArgs e)
{
MethodInvoker method = delegate
{
uiSomeTextBox.Text = "some text";
};
if (InvokeRequired)
BeginInvoke(method);
else
method.Invoke();
}
You can safe work with WFA like in bacroundWorker
When algorithm in BackGrounWorker come to return, he generate event about end of work. But thread object can still continue to exist. It's inner singularity Windows and CLR, - Threads that may exist for some time after death.
There are times in my application, when I need to invoke my timer manually.
I've tried the following:
int originalInterval = t.Interval;
t.Interval = 0;
t.Interval = originalInterval;
but it wasn't consistent.
I've created a new timer, inheriting from System.Timers.Timer, and exposed a "Tick" method - but the problem was that the "Elapsed" event then fired synchronously.
When I implemented the "Tick" with a new Thread - the results were, again, not consistent.
Is there a better way to implement it?
I once had the same problem, so I used the AutoResetEvent to know if the Elapsed was invoked successfully:
/// <summary>
/// Tickable timer, allows you to manually raise a 'Tick' (asynchronously, of course)
/// </summary>
public class TickableTimer : System.Timers.Timer
{
public new event ElapsedEventHandler Elapsed;
private System.Threading.AutoResetEvent m_autoResetEvent = new System.Threading.AutoResetEvent(true);
public TickableTimer()
: this(100)
{
}
public TickableTimer(double interval)
: base(interval)
{
base.Elapsed += new ElapsedEventHandler(TickableTimer_Elapsed);
}
public void Tick()
{
new System.Threading.Thread(delegate(object sender)
{
Dictionary<string, object> args = new Dictionary<string, object>
{
{"signalTime", DateTime.Now},
};
TickableTimer_Elapsed(this, Mock.Create<ElapsedEventArgs>(args));
}).Start();
this.m_autoResetEvent.WaitOne();
}
void TickableTimer_Elapsed(object sender, ElapsedEventArgs e)
{
m_autoResetEvent.Set();
if (this.Elapsed != null)
this.Elapsed(sender, e);
}
}
It feels like you should look at your design a bit. Typically I try to avoid having the event handler method contain the actual work being done, but I rather try to let it be just a trigger, calling some other method that performs the work. That way you can invoke that other method from anywhere else as well:
private void Timer_Tick(object sender, EventArgs e)
{
new Thread(MethodThatDoesTheWork).Start();
}
private void MethodThatDoesTheWork()
{
// actual work goes here
}
Now, you can invoke MethodThatDoesTheWork from anywhere else within the class (either synchronously or asynchronously using a separate thread).
Alternatively, if MethodThatDoesTheWork should always be an asynchronous call, you can spawn the thread inside that method instead:
private void MethodThatDoesTheWork()
{
new Thread(() =>
{
// work code goes here
}).Start();
}
In these samples I have manually created threads. You can use that approach, the ThreadPool, Task or whatever other method of calling code asychronously, whichever fits best in your context.
Normally you shouldn’t need to fire a timer manually — you can always just run the event itself in a new thread. By and large, that’s basically what the timer does, and since you want to fire it manually, you don’t need the timer (for that manual invocation).
You didn’t specify any details as to what you mean by “not consistent”. The following should normally work:
Thread thread = new Thread(myDelegate);
thread.Start();
Of course, myDelegate can be a lambda in case you need to pass parameters:
Thread thread = new Thread(() => myMethod(param1, param2));
thread.Start();