Wait Event in Application - c#

I want to wait for Event when I get data in my C# Project.
When program read some data GetData other program creates an event at the end of read this data (call EventForGetData).
So, I need to wait for EventForGetData that finish read.
I wrote this code for this task but believe this code might write more optimal.
public static bool WaitEvent = true;
public void EventForGetData(string variable)
{
WaitEvent = false;
}
public static string ForWaitGetData()
{
WaitEvent = true;
while (WaitEvent)
{
System.Threading.Thread.Sleep(5);
Application.DoEvents();
}
return Variable;
}
public object GetData(){
// start read data
...
// Wait for finish to read data
ForWaitGetData();
// finish read data
...
return MyObject;
}

Try to use Task the first Task is to get your data, at the end do your processing or launch your event:
Example
Task task = Task.Factory.StartNew(() =>
{
//put you code here the first one
}).ContinueWith((rs) =>{
//Launch your event or anything you want
});
Note: the code that you will put inside the ContinueWith will be executed after the code that you write in the StartNew.

Related

Replace 'BackgroundWorker' With 'Thread '

I want to replace BackgroundWorker in my winform application with a Thread.
The goal is do the the jobs in a new thread other than UI-thread & prevent program hang during run.
So i did this :
private void radBtn_start_Click(object sender, EventArgs e)
{
try
{
string thread_name = "trd_" + rnd.Next(99000, 10000000).ToString();
Thread thread = new Thread(new ThreadStart(Thread_Method));
thread.Name = thread_name;
thread.Start();
}
catch (System.Exception ex)
{
MessageBox.Show("Error in radBtn_start_Click() Is : " + ex.ToString());
}
}
public void Thread_Method()
{
...Some Jobs
Thread.Sleep(20000);
...Some Jobs After Delay
Thread.Sleep(20000);
...Some Jobs After Delay
this.Invoke(new MethodInvoker(delegate
{
radTextBoxControl1.Text += DateTime.Now.ToString() + " : We are at end of search( " + radDropDownList1.SelectedItem.Tag + " ) = -1" + Environment.NewLine;
}));
}
But after running these codes UI hangs during sleep.
What is the correct codes for my purpose?
You don't have to create a new Thread, your process already has a pool of threads anxiously waiting to do something for you
Usually the threads in the thread pool are used when you use async-await. However, you can also use them for heavy calculations
My advice is to make your thread_method async. This has the advantage, that whenever your thread_method has to wait idly for another process to finish, like writing data to a file, fetching items from a database, or reading information from the internet, the thread is available for the thread pool to do other tasks.
If you are not familiar with async-await: this interview with Eric Lippert really helped me to understand what happens when you use async-await. Search somewhere in the middle for async-await.
One of the nice things about async-await, is that the executing thread has the same "context" as the UI-thread, so this thread can access UI-elements. No need to check for InvokeRequired or to call Invoke.
To make your ThreadMethod async:
declare it async
instead of TResults return Task<TResult>; instead of void return Task
only exception: async event handlers return void
whenever you call other methods that have an async version, call this async version, start awaiting when you need the results of the async task.
public async Task FetchCustomerAddress(int customerId)
{
// fetch the customer address from the database:
using (var dbContext = new OrderDbContext(...))
{
return await dbContext.Customers
.Where(customer => customer.Id == customerId)
.Select(customer => new Address
{
Name = customer.Name,
Street = customer.Street,
... // etc
})
.FirstOrDefaultAsync();
}
}
public async Task CreateCustomerOrder(
int customerId, IEnumerable orderLines)
{
// start reading the customer Address
var taskReadCustomerAddress = this.FetchCustomerAddress(customerId);
// meanwhile create the order
CustomerOrder order = new CustomerOrder();
foreach (var orderLine in orderLines)
{
order.OrderLines.Add(orderLine);
}
order.CalculateTotal();
// now you need the address of the customer: await:
Address customerAddress = await taskReadCustomerAddress;
order.Address = customerAddress;
return order;
}
Sometimes you don't have to wait idly for another process to finish, but you need to do some heavy calculations, and still keep your UI-thread responsive. In older applications you would use the BackgroundWorker for this, in newer applications you use Task.StartNew
For instance, you have a button, and a menu item that both will start some heavy calculations. Just like when using the backgroundworker you want to show some progress. While doing the calculations, both the menu item and the button need to be disable.
public async Task PrintCustomerOrdersAsync(
ICollection<CustomerOrderInformation> customerOrders)
{
// while creating the customer orders: disable the button and the menu items
this.buttonPrintOrders.Enabled = false;
this.menuItemCreateOrderLines.Enabled = false;
// show the progress bar
this.ProgressBarCalculating.MinValue = 0;
this.ProgressBarCalculating.MaxValue = customers.Count;
this.ProgressBarCalculating.Value = 0;
this.ProgressBarCalculating.Visible = true;
List<Task<PrintJob>> printJobs = new List<Task<PrintJob>>();
foreach (CustomerOrderInformation orderInformation in customerOrders)
{
// instead of BackGroundworker raise event, you can access the UI items yourself
CustomerOrder order = this.CreateCustomerOrder(orderInformation.CustomerId,
orderInformation.OrderLines);
this.ProgressBarCalculating.Value +=1;
// print the Order, do not await until printing finished, create next order
printJobs.Add(this.Print(order));
}
// all orders created and sent to the printer. await until all print jobs complete:
await Task.WhenAll(printJobs);
// cleanup:
this.buttonPrintOrders.Enabled = true;
this.menuItemCreateOrderLines.Enabled = true;
this.ProgressBarCalculating.Visible = false;
}
By the way: in a proper design, you would separate the enabling / disabling the items from the actual processing:
public async Task PrintCustomerOrdersAsync(ICollection<CustomerOrderInformation> customerOrders)
{
this.ShowBusyPrintingOrders(customerOrders.Count);
await this.PrintOrdersAsync(customerOrders);
this.HideBusyPrintingOrders();
}
Now to start printing the orders when a button is pressed, there are two possibilities:
If the process is mostly waiting for others: async event handler
If there are really heavy calculations (longer than a second?): start a task that does the calculations
No heavy calculations:
// async event handler has void return value!
private async void ButtonPrintOrdersClickedAsync(object sender, ...)
{
var orderInformations = this.GetOrderInformations();
await PrintCustomerOrdersAsync(orderInformations);
}
Because I don't have anything other useful to do, I await immediately
Heavy calculations: start a separate task:
private async Task ButtonCalculateClickedAsync(object sender, ...)
{
var calculationTask = Task.Run(() => this.DoHeavyCalculations(this.textBox1.Text);
// because you didn't await, you are free to do something else,
// for instance show progress:
while (!calculationTask.Complete)
{
// await one second; UI is responsive!
await Task.Delay(TimeSpan.FromSeconds(1));
this.ProgressBar.Value += 1;
}
}
Be aware: using these methods, you can't stop the process. So you are in trouble if the operator wants to close the application while you are still printing.
Just like your background thread, every method that supports cancellation should regularly check if cancellation is requested. The advantage is, that this checking is also done in the .NET methods that support cancellation, like reading database information, writing a file, etc. The backgroundWorker couldn't cancel writing to a file.
For this we have the CancellationTokenSource
private CancellationTokenSource cancellationTokenSource;
private Task taskPrintOrders;
public async Task PrintCustomerOrdersAsync(ICollection<CustomerOrderInformation> customerOrders)
{
this.ShowBusyPrintingOrders(customerOrders.Count);
using (this.cancellactionTokenSource = new CancellationTokenSource())
{
taskPrintOrders = this.PrintOrdersAsync(customerOrders, this.cancellationTokenSource.Token);
await taskPrintOrders;
this.HideBusyPrintingOrders();
}
private void CancelPrinting()
{
this.cancellationTokenSource?.Cancel();
}
If you want to cancel and wait until finished, for instance when closing the form:
private bool TaskStillRunning => this.TaskPrinting != null && !this.TaskPrinting.Complete;
private async void OnFormClosing(object sender, ...)
{
if (this.TaskStillRunning)
{
bool canClose = this.AskIfCanClose();
if (!canClose)
eventArgs.Cancel = true;
else
{
// continue closing: stop the task, and wait until stopped
this.CancelPrinting();
await this.taskPrintOrders;
}
}
}
This will work in separate thread without hanging your UI.
Use new Thread
new Thread(delegate()
{
Thread_Method();
}).Start();
or Task.run
Task.Run(() =>
{
Thread_Method();
});

Notify the ActionBlock is completed to another class

I have written a method to implement TPL ActionBlock, which will do a function to find the XPath of the element I am Posting to the block. I am sending the element from a real-time application (whenever the user finds an element Post it to the block). Now, I want to check the block is completed or not when I call a save button from another class. The logic is if the ActionBlok is completed when we click the save button element will save with some save logic, otherwise show a message box not yet ready. For the first time, this idea is working, but from the second element onwards the Actionblock is not accepting any. I am using block.Complete() and block.Completion.Wait() for the save check. Now I can show I am calling the code/logic.
Once create an element, post it ActionBlock
Class1
......
jobQ.Enqueue(familarizedElement);
......
Inside the ActionBlock
Class2
public class TPLCommonDataFlow
{
private ActionBlock<Element> _jobs;
public static bool TPLFlowStatus = false;
public static string JobStatus = string.Empty;
public TPLCommonDataFlow()
{
var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 2,
};
_jobs = new ActionBlock<Element>((job) =>
{
Thread.Sleep(5);
File.WriteAllText("C:\\Temp\\A.txt", "Started" + _jobs.InputCount.ToString());
JobStatus = "started";
Familiarization.FindAndUpdateXPath(job);
File.WriteAllText("C:\\Temp\\A.txt", "Finished");
}, executionDataflowBlockOptions);
_jobs.Complete();
//Wait for all messages to propagate through the network
_jobs.Completion.Wait();
//Checking all jobs are completed or not, if completed changing the boo, value.
if (_jobs.InputCount == 0)
{
TPLFlowStatus = true;
JobStatus = "stoped";
}
}
}
For the save I am checking the TPLFlowStatus boolean
Class3
if (class2.TPLFlowStatus == true)
{
//Save Logic
}
else
{
//Message Box showing Not Ready
}
Now what I want is to check each time the job is completed or not for each element in the save logic. If the block having two elements in Queue and one is finished, then the MessageBox needs to popup once the save button pressed. If all completed in the block, then need to go to the save logic.
The issue your seeing is that when a block is completed it will no longer accept new messages, you've told the block your done sending messages. To start sending a new batch of messages you can either keep the block alive by not calling complete and tracking the batch completion another way or you can just reset the block. A simple worker like this might be what you're looking for:
public class DataflowWorker
{
private ActionBlock<string> _jobs;
private void BuildJobsHandler()
{
_jobs = new ActionBlock<string>(x => Console.WriteLine(x) /*Do your work in the action block*/);
}
public async Task Enque(string element)
{
await _jobs.SendAsync(element);
}
public async Task CompleteJobsAndSave()
{
_jobs.Complete();
await _jobs.Completion;
//Save data when complete
BuildJobsHandler();
}
}

C# return before await - without starting a new Task

This is for an iOS app written in Xamarin. All my application code runs in the main thread (i.e. the UI thread).
The UI code does something as follows:
public async void ButtonClicked()
{
StartSpinner();
var data = await UpdateData();
StopSpinner();
UpdateScreen(data);
}
The UpdateData function does something as follows:
public Task<Data> UpdateData()
{
var data = await FetchFromServer();
TriggerCacheUpdate();
return data;
}
TriggerCacheUpdate ends up calling the following function defined below
public Task RefreshCache()
{
var data = await FetchMoreDataFromServer();
UpdateInternalDataStructures();
}
My question is how should TriggerCacheUpdate be written? The requirements are:
Can't be async, I don't want UpdateData and consequently
ButtonClicked to wait for RefreshCache to complete before
continuing.
UpdateInternalDataStructures needs to execute on the main (UI) thread, i.e. the thread that all the other code shown above executes on.
Here are a few alternatives I came up with:
public void TriggerCacheUpdate()
{
RefreshCache();
}
The above works but generates a compiler warning. Moreover exception handling from RefreshCache doesn't work.
public void TriggerCacheUpdate()
{
Task.Run(async() =>
{
await RefreshCache();
});
}
The above violates requirement 2 as UpdateInternalDataStructures is not executed on the same thread as everything else.
A possible alternative that I believe works is:
private event EventHandler Done;
public void TriggerCacheUpdate()
{
this.task = RefreshCache();
Done += async(sender, e) => await this.task;
}
Task RefreshCache() {
var data = await FetchMoreDataFromServer();
UpdateInternalDataStructures();
if (Done != null) {
Done(this, EventArgs.Empty);
}
}
Does the above work? I haven't ran into any problems thus far with my limited testing. Is there a better way to write TriggerCacheUpdate?
It's hard to say without being able to test it but it looks like your trigger cache update method is fine, it's your RefreshCache that needs to change. Inside of RefreshCache you are not waiting in the UI thread for the result of "data" to return so set the ConfigureAwait to false.
public async Task RefreshCache()
{
var data = await FetchMoreDataFromServer().ConfigureAwait(false);
UpdateInternalDataStructures();
}
Your event handler is async. That means, that even if you await for a Task to complete, that your UI remains responsive. So even if you would await for the TriggerCacheUpdate to return, your UI would remain responsive.
However, if you are really certain that you are not interested in the result of TriggerCachUpdate, then you could start a Task without waiting for it:
public Task<Data> UpdateData()
{
var data = await FetchFromServer();
Task.Run( () => TriggerCacheUpdate());
return data;
}
Note: careful: you don't know when TriggerCachUpdate is finished, not even if it ended successfully or threw an exception. Also: check what happens if you start a new TriggerCacheUpdate task while the previous one is not finished yet.
For those who want to use Task.Factory.StartNew, see the discussion about it in MSDN:
Task.Run vs Task.Factory.StartNew

Do work without blocking the gui thread

I have a c# windows forms application and use a library which does not provide async-await functionality.
When I press on a button I want to do some work (webrequesting).
While doing this work I dont want to freeze my gui.
I tried several approaches, for example:
public static Task<bool> LoginUser(string username, string password)
{
return Task.Factory.StartNew(() =>
{
try
{
session = new AuthenticatedSession<User>(new User(username), Cryptography.GetMd5(password));
return true;
}
catch (InvalidAuthenticationException)
{
return false;
}
});
}
When I call LoginUser("foo", "bar").Result the gui freezes until the work is done (I understand that this is not async because I can't await new AuthenticatedSession<...
So I look for something like:
Create a thread with a action as parameter
Return the value from the thread
End the thread
Try forcing a new thread (or WorkerThread) instead of using the TaskFactory.
Thread t = new Thread (delegate()
{
try
{
session = new AuthenticatedSession<User>(new User(username), Cryptography.GetMd5(password));
Success(); //coded below
}
catch (InvalidAuthenticationException)
{
Fail();
}
});
t.Start();
Your list requires that we return a value, all we really can do is call a method or set state indicating the return value or even signal (ManualResetEventSlim) if you want some blocking, but your requirements state you want non-blocking.
To resume execution or signal the GUI that your process is done you would invoke some method on the UI thread, like this:
void Success() {
Invoke((MethodInvoker) delegate {
SomeMethodOnTheUI();
});
}
This is basically an async/callback strategy.

c# do the equivalent of restarting a Task with some parameter

The main idea here is to fetch some data from somewhere, when it's fetched start writing it, and then prepare the next batch of data to be written, while waiting for the previous write to be complete.
I know that a Task cannot be restarted or reused (nor should it be), although I am trying to find a way to do something like this :
//The "WriteTargetData" method should take the "data" variable
//created in the loop below as a parameter
//WriteData basically do a shedload of mongodb upserts in a separate thread,
//it takes approx. 20-30 secs to run
var task = new Task(() => WriteData(somedata));
//GetData also takes some time.
foreach (var data in queries.Select(GetData))
{
if (task.Status != TaskStatus.Running)
{
//start task with "data" as a parameter
//continue the loop to prepare the next batch of data to be written
}
else
{
//wait for task to be completed
//"restart" task
//continue the loop to prepare the next batch of data to be written
}
}
Any suggestion appreciated ! Thanks. I don't necessarily want to use Task, I just think it might be the way to go.
This may be over simplifying your requirements, but would simply "waiting" for the previous task to complete work for you? You can use Task.WaitAny and Task.WaitAll to wait for previous operations to complete.
pseudo code:
// Method that makes calls to fetch and write data.
public async Task DoStuff()
{
Task currTask = null;
object somedata = await FetchData();
while (somedata != null)
{
// Wait for previous task.
if (currTask != null)
Task.WaitAny(currTask);
currTask = WriteData(somedata);
somedata = await FetchData();
}
}
// Whatever method fetches data.
public Task<object> FetchData()
{
var data = new object();
return Task.FromResult(data);
}
// Whatever method writes data.
public Task WriteData(object somedata)
{
return Task.Factory.StartNew(() => { /* write data */});
}
The Task class is not designed to be restarted. so you Need to create a new task and run the body with the same Parameters. Next i do not see where you start the task with the WriteData function in its body. That will property Eliminate the call of if (task.Status != TaskStatus.Running) There are AFAIK only the class Task and Thread where task is only the abstraction of an action that will be scheduled with the TaskScheduler and executed in different threads ( when we talking about the Common task Scheduler, the one you get when you call TaskFactory.Scheduler ) and the Number of the Threads are equal to the number of Processor Cores.
To you Business App. Why do you wait for the execution of WriteData? Would it be not a lot more easy to gater all data and than submit them into one big Write?
something like ?
public void Do()
{
var task = StartTask(500);
var array = new[] {1000, 2000, 3000};
foreach (var data in array)
{
if (task.IsCompleted)
{
task = StartTask(data);
}
else
{
task.Wait();
task = StartTask(data);
}
}
}
private Task StartTask(int data)
{
var task = new Task(DoSmth, data);
task.Start();
return task;
}
private void DoSmth(object time)
{
Thread.Sleep((int) time);
}
You can use a thread and an AutoResetEvent. I have code like this for several different threads in my program:
These are variable declarations that belong to the main program.
public AutoResetEvent StartTask = new AutoResetEvent(false);
public bool IsStopping = false;
public Thread RepeatingTaskThread;
Somewhere in your initialization code:
RepeatingTaskThread = new Thread( new ThreadStart( RepeatingTaskProcessor ) ) { IsBackground = true; };
RepeatingTaskThread.Start();
Then the method that runs the repeating task would look something like this:
private void RepeatingTaskProcessor() {
// Keep looping until the program is going down.
while (!IsStopping) {
// Wait to receive notification that there's something to process.
StartTask.WaitOne();
// Exit if the program is stopping now.
if (IsStopping) return;
// Execute your task
PerformTask();
}
}
If there are several different tasks you want to run, you can add a variable that would indicate which one to process and modify the logic in PerformTask to pick which one to run.
I know that it doesn't use the Task class, but there's more than one way to skin a cat & this will work.

Categories

Resources