How to call a procedure after finish the Task - c#

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.

Related

Re-synchronize Process.RedirectStandardOutput

Background
I'm writing a c# wrapper for a node.js application. In this wrapper I continuously read the standard output via Process.RedirectStandardOutput. The event is bound to the function onOutputDataReceived, in an instance of the class ProcessManager. In this same instance, there is also an instance of a custom event system.
[ProcessManager]
EventSystem eventSystem;
private void Start()
{
[...]
process.OutputDataReceived += onOutputDataReceived;
[...]
}
private void onOutputDataReceived(object sender, DataReceivedEventArgs e)
{
[...]
eventSystem.call(eventName, args);
}
[EventSystem]
List<EventHandler> eventList;
public Boolean call(String eventName, dynamic args)
{
[...]
foreach (EventHandler handler in eventList)
{
handler(args);
}
[...]
}
The problem occurs when the event is being called. Here is an example from a winforms application using my wrapper.
Wrapper.ProcessManager procMan;
procMan.eventSystem.on(eventName, (a) =>
{
button1.Text = someValue;
});
When run, the application crashes with the message
Cross-thread operation not valid: Control 'button1' accessed from a thread other than the thread it was created on
My issue, as I understand it, is this:
onOutputDataReceived is being executed asynchronously, in its own thread. As this same thread, only meant to be handling the output, goes on to call the events, I'm unintentionally multithreading my wrapper, making life harder for anyone implementing it.
Basically,
I need to run the line eventSystem.call() in the same thread that maintains the rest of the ProcessManager instance, as soon as new output data has been received as possible. Any ideas on how this best can be achieved?
A solution I've thought of is something like this
[ProcessManager]
Queue<string> waiting = new Queue<string();
EventSystem eventSystem;
private void onOutputDataReceived(object sender, DataReceivedEventArgs e)
{
[...]
waiting.Enqueue(eventName);
}
private void WhenReady()
{
while(waiting.Count > 0)
eventSystem.call(waiting.Dequeue());
}
As far as I can see, this would involve some kind of polling every x milliseconds, which doesn't feel like a clean solution. Also, it seems to me as if such a solution would be way too expensive for when no messages are being received and too slow for when some are.
The code that executes the nodejs process and reads its output should not need to know about the threading requirements of event subscribers. Make the subscriber satisfy its own requirements:
(a) =>
{
Invoke(new Action(() => button1.Text = someValue)); //marshal to UI thread
}
Your tentative solution would not work because it would block the UI thread.
Also, waiting is being used in an unsynchronized way... This is an unrelated bug.

How to block until an event is fired in c#

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.

Start second method after first method is finished with thread functionality c#

I have a method which is rebuilding the product catalog of a webshop. This is neccessary after I change some product information. After the rebuilding method I would like to start a second method to generate full text index of the webshop. I can watch the status of the first method (RebuildCatalog). If the status is "RebuildFinished" then I would like to start the second method (GenerateFullTextIndex). I would like to use Threads functionality. Does someone can create an example of how to implementate this scenario?
I would like to use Threads functionality.
It really doesn't sound like you do. Starting one method after another finishes is as simple as:
var status = RebuildCatalog();
if (status == Status.RebuildFinished)
{
GenerateFullTextIndex();
}
No threading required. If you really think you need multiple threads, you should explain why you think they'll help. At what point do you need to perform multiple tasks concurrently?
Well, if you want to use a multiple threads and oranize your calls in chain so they are executed on another thread, but in sequence, and you are using .NET Framework 4.0>, you can use a Task Parallelism, like for example using Task::ContinueWith method.
Example (preudocode from MSDN):
Task<byte[]> getData = new Task<byte[]>(() => GetFileData());
Task<double[]> analyzeData = getData.ContinueWith(x => Analyze(x.Result));
Task<string> reportData = analyzeData.ContinueWith(y => Summarize(y.Result));
getData.Start();
//or...
Task<string> reportData2 = Task.Factory.StartNew(() => GetFileData())
.ContinueWith((x) => Analyze(x.Result))
.ContinueWith((y) => Summarize(y.Result));
Using events would seem to be simpler than watching the status.
In your rebuild catalog code fire a "finished" event on completion:
public event EventHandler<EventArgs> RebuildFinished;
private void Rebuild(...)
{
// Rebuild the catalog
this.RebuildFinished(this, new EventArgs(...));
}
Then handle it:
this.catalog.RebuildFinished += this.RebuildFinished;
private void RebuildFinished(object sender, EventArgs e)
{
// Rebuild the index
}
Now both of these can (and probably should) be using threads to ensure that the UI of your application stays responsive:
this.catalogThread = new Thread(new ThreadStart(this.catalog.Rebuild));
As I can assume from your question your rebuilding method probably takes up considerable time and that is why you want to run in a separate thread. Therefore I would suggest implementing Event based async pattern. When your rebuilding (async) method finishes it will throw finished event with AsyncCompletedEventArgs (which you can subclass to pass your result status) and from there you will start your second method.
BackgroundWorker bw1 = new BackgroundWorker();//To rebuild catalog.
BackgroundWorker bw2 = new BackgroundWorker();//To generate text.
public Form1()
{
InitializeComponent();
bw1.DoWork += bw1_DoWork;
bw1.RunWorkerCompleted += bw1_RunWorkerCompleted;
bw2.DoWork += bw2_DoWork;
bw2.RunWorkerCompleted += bw2_RunWorkerCompleted;
bw1.RunWorkerAsync();//Start new thread. - Rebuild catalog.
}
void bw1_DoWork(object sender, DoWorkEventArgs e)
{
//Rebuild catalog.
}
void bw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bw2.RunWorkerAsync();//Generate text.
}
void bw2_DoWork(object sender, DoWorkEventArgs e)
{
//Generate text.
}
void bw2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Whatever...
}

Thread Safe calls to Winform controls

References:
http://msdn.microsoft.com/en-us/library/ms171728.aspx
http://stackoverflow.com/questions/5408155/how-to-make-delegate-thread-sta
I wanted to create a new Thread and make it STA therefore I was not able to use asynchronous delegates or BackgroudWorker (as mentioned in references link 1) Therefore I end up creating a Thread of my own make it STA and attach a callback to know when the Task is complete. The code is something like below and even though I am using invoke required, I still get InvalidOperationException (once in a while)
delegate UpdateEventHander(Object sender, EventArgs e);
class MyTask{
// to generate an event
public event UpdateEventHandler Finished;
public void Start(){
Result = // something that require the thread to be STA.
Finished(this, EventArgs.Empty);
}
public Result GetResult(){
return Result;
}
}
Class Foo : Form{
// It has many UI Controls obviously
public void doSomething(){
MyTask task = new MyTask();
task.Finished += new UpdateEventHander(CompletionHandler);
Thread thread = new Thread(new ThreadStart(task.Start));
thread.setAppartmetnState(AppartmentState.STA);
thread.start();
}
public void CompletionHandler(Object sender, EventArgs e){
MyTask task = (MyTask) sender;
if (oneOfMyControls.InvokeRequired){
delegateToUpdateUIconrols del = new delegateToUpdateUIconrols(updateUIControls);
del.invoke();
}else{
UpdateUIControls();
}
}
public delegate void delegateToUpdateUIconrols();
public void UpdateUIControls(){
// It updates UI controls
// Datagrid view value properties like backgroud color and stuff.
// change text in the label.
}
}
Question 1: Which thread will UpdateUIControls execute ? - if you say "Main UI Thread" - then in that case how will the system know if its supposed to run in Main UI thead and NOT some OTHER thread? I am not passing any reference (about Main UI thread) when I call invoke() .. so invoke() is technically executed on the same thread..
Question 2: Once in a while, I get the InvalidOperationException. Exactly this one
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/6b450a21-e588-414a-afae-9adabfd03674/
If UpdateUIControls is executing in the main UI thread, there should be not prblem, Right? So, I guess answer to my question really depends upon question 1.
I will appreciate if someone share his/her wisdom on this
Karephul
Controls have thread-affinity; you can only safely talk to them from their creating thread.
You are checking InvokeRequired; however, you are mixing up Delegate.Invoke (runs on the current thread) with Control.Invoke (runs on the UI thread); very different meaning. It should be:
oneOfMyControls.Invoke(del [, args]);

Whats wrong with my AutoResetEvent code?

I have this code which seems pretty straightforward but the AutoResetEvent never gets signalled. Nothing seems to get returned from the web services and the WaitAll just times out after ten seconds. Everything works fine without the threading jiggerypokery so its not a web service issue. What am I doing wrong?
AutoResetEvent[] autoEvents;
ObservableCollection<Tx3.ResourceService.ResourceTime> resourceTime;
ObservableCollection<Tx3.ResourceService.ResourceTimeDetail> resourceTimeDetail;
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
autoEvents = new AutoResetEvent[]
{
new AutoResetEvent(false),
new AutoResetEvent(false),
};
var resourceService = getResourceServiceClient();
// Get ResourceTime data for this user
resourceService.ListResourceTimeAsync(CategoryWorkItemId, ResourceId);
resourceService.ListResourceTimeCompleted += new EventHandler<Tx3.ResourceService.ListResourceTimeCompletedEventArgs>(resourceService_ListResourceTimeCompleted);
// Get ResourceTimeDetails
resourceService.ListResourceTimeDetailAsync(CategoryWorkItemId, ResourceId);
resourceService.ListResourceTimeDetailCompleted += new EventHandler<ListResourceTimeDetailCompletedEventArgs>(resourceService_ListResourceTimeDetailCompleted);
WaitHandle.WaitAll(autoEvents, 10000);
System.Diagnostics.Debug.WriteLine("do something with both datasets");
}
void resourceService_ListResourceTimeCompleted(object sender, Tx3.ResourceService.ListResourceTimeCompletedEventArgs e)
{
resourceTime = e.Result;
autoEvents[0].Set();
}
void resourceService_ListResourceTimeDetailCompleted(object sender, ListResourceTimeDetailCompletedEventArgs e)
{
resourceTimeDetail = e.Result;
autoEvents[1].Set();
}
I can offer a naive first guess: it looks like you're adding the event handlers after calling the methods that start the asynchronous operations; it's possible there's a race condition in there or some other issue. Could you switch the order of operations so you attach the event handler, and then begin the operation?
These are AutoResetEvent objects -- looks like you want a ManualResetEvent -- the auto version triggers anything waiting, but immediately resets. Manual ones stay triggered so if the callback happens before you get to the WaitAll, it'll just fall through immediately.
Also, qid is correct -- you're attaching your event handlers too late too...so there's two different bugs going on here.
Are you using this code on a thread that is marked with the STA attribute, for example the main UI thread? If so, the WaitAll method is not supported on these threads.
Check here.

Categories