I've created a simple thread controller class managing the thread's execution, here its code:
public class ThreadController {
int waitCount;
Thread myThread;
public ThreadController() {
//
}
public void StartThread() {
waitCount = 0;
// launch a thread to show an alert when conditions are met!
myThread = new Thread(new ThreadStart(ThreadAction));
myThread.IsBackground = true;
myThread.Start();
}
// method is async as it call an async method itself!
void ThreadAction() {
while (myThread.IsAlive) {
Thread.Sleep(5000);
bool doStop = DoStopTest().Result; // some async function testing stop criterion
if (doStop) {
MainForm.BeginInvoke(new MethodInvoker(delegate() {
MessageBox.Show("Thread stopped!");
}));
//
myThread.Abort();
}
++waitCount;
if (waitCount >= 15) {
myThread.Abort();
}
Thread.Sleep(5000);
}
}
}
Now, I want to make sure the above created threads (there might be several) are killed when I close the MainForm, which I read should be done in the FormClosing event as follows:
void Main_FormClosing(object Sender, FormClosingEventArgs e) {
// unfortunately, an error is thrown when I call following line...
Environment.Exit(Environment.ExitCode);
}
The Environment.Exit call actually generates some weird exceptions... Sometimes a "vhost32.exe stopped working", sometimes an error System.ComponentModel.Win32Exception (0x80004005): Error creating window handle or other painting events that use "Invalid Parameters"...
Am I missing something here? What is the suggested way to cleanly close the form with all associated threads, without running into errors?
The code would be a lot clearer if you used tasks and async/await. DoStopTest() seems to return a Task already, so there's no need to use a raw Thread.
The code could be something as simple as a loop :
public async Task MyTestAndWait()
{
await Task.Delay(5000);
var waitCount=0;
while( waitCount++ < 15 && !(await DoStopTest()))
{
await Task.Delay(10000);
}
MessageBox.Show("Thread stopped!");
}
After each call to await execution resumes on the original synchronization context. For desktop applications, that's the UI thread. That means there's no need to use BeginInvoke
Threads should not be aborted. The correct way is to check a thread-safe signal, like a ManualResetEvent that's raised when a thread needs to exit. When signalled, the thread's code itself should exit.
Using a lot of events can get a bit messy which is why .NET 4.5 added the CancellationToken and CancellationTokenSource classes that can be used to notify both threads and Tasks they need to cancel and exit gracefully.
public async Task MyTestAndWait(CancellationToken ct,int initialDelay,int pollDelay)
{
await Task.Delay(initialDelay,ct);
var waitCount=0;
while(!ct.IsCancellationRequested && waitCount++ < 15 && !(await DoStopTest()))
{
await Task.Delay(pollDelay,ct);
}
MessageBox.Show("Poll stopped!");
}
This will cancel the delays and the loop but it won't cancel the call to DoStepTest(). That method will have to accept a CancellationToken parameter as well
CancellationTokens are created by CancellationTokenSource classes. One of the overloads accepts a timeout, which could be used to cancel the overall operation :
public async void SendSMS_Click(object sender, EventArgs args)
{
var cts=new CancellationTokenSource(TimeSpan.FromMinutes(15));
await MyTestAndAwait(cts.Token,5000,10000);
}
The cts could be stored in a field, to allow cancellation due to another event like a button click :
CancellationTokenSource _cts;
public async void SendSMS_Click(object sender, EventArgs args)
{
SendSMS.Enabled=false;
Cancel.Enabled=true;
_cts=new CancellationTokenSource(TimeSpan.FromMinutes(15);
await MyTestAndAwait(cts.Token,5000,10000);
_cts=null;
SendSMS.Enabled=true;
Cancel.Enabled=false;
}
public async void Cancel_Click(object sender, EventArgs args)
{
_cts?.Cancel();
}
The same code can be used to signal cancellation when closing the form :
void Main_FormClosing(object Sender, FormClosingEventArgs e)
{
_cts.?Cancel();
}
BTW there's no reason to call Environment.Exit() in the form's Closing or Closed events. Closing the main form will end the application unless there's another thread running.
UPDATE
It looks like the actual question is how to verify that an SMS was sent by polling for its send status. The code in this case would be different, while still using task. The method shouldn't have any reference to the UI so it can be moved to a separate Service-layer class. After all, changing providers shouldn't result in changing UIs
Assuming HttpClient is used, it could look like this :
//In an SmsService class
public async Task<(bool ok,string msg)> SendSmsAsync(string phone,string message,CancellationToken ct)
{
var smsMsg=BuildSmsContent(phone,string);
await _httpClient.PostAsync(smsMsg,ct);
//wait before polling
await Task.Delay(_initialDelay,ct);
for(int i=0;i<15 && !ct.IsCancellationRequested;i++)
{
var checkMsg=CheckStatusContent(phone,string);
var response=await _httpClient.GetAsync(check,ct);
if (ct.IsCancellationRequested) break;
//Somehow check the response. Assume it has a flag and a Reason
var status=ParseTheResponse(response);
switch(status.Status)
{
case Status.OK:
return (ok:true,"Sent");
case Status.Error:
return (ok:failed,status.Reason);
case Status.Pending:
await Task.Delay(_pollDelay,ct);
break;
}
}
return (ok:false,"Exceeded retries or cancelled");
}
This method could be used from a button event :
CancellationTokenSource _cts;
public async void SendSMS_Click(object sender, EventArgs args)
{
DisableSending();
var phone=txtPhone.Text;
var message=txtMessage.Text;
_cts=new CancellationTokenSource(TimeSpan.FromMinutes(15);
var (ok,reason)=await _smsService.SendSmsAsync(phone,message,cts.Token);
_cts=null;
if (ok)
{
MessageBox.Show("OK");
}
else
{
MessageBox.Show($"Failed: {reason}");
}
EnableSending();
}
public void EnableSending()
{
SendSMS.Enabled=true;
Cancel.Enabled=false;
}
public void DisableSending()
{
SendSMS.Enabled=false;
Cancel.Enabled=true;
}
Related
I have a C# GUI application where when one clicks on a button and then MyMethod starts running async way and it continuously(inside a do while loop) calls MyTask. MyTask writes and reads data from a port. And these data is passed to MyProgressMethod for further proccess.
I want to implement a button which would first cancel/stop MyTask and then close the port.
Being new with this async way, I relied on some online examples which I stumbled upon and the rest were a difficult to grasp. Based on what I read, I came up with the following to achieve cancellation with a button. But I don't quite understand the mechanism and wondering whether the following way is correct:
Declaring a CancellationTokenSource object at the very beginning of class:
CancellationTokenSource my_cancelationTokenSource = null;
The button click event. Button event calls MyMethod:
private void Button_Click(object sender, RoutedEventArgs e)
{
//Some code
MyMethod();
}
MyMethod calls MyTask each second and passes data to MyProgressMethod:
private async void MyMethod()
{
my_cancelationTokenSource = new CancellationTokenSource();
do
{
await Task.Delay(1000);
//Process some code
byte[] my_received_data = await MyTask(my_sent_data, my_cancelationTokenSource.Token);
MyProgressMethod(my_received_data, my_sent_data);
}
while (true);
}
MyTask read and writes to the port(Needs to be cenceledbefore the port is closed):
private async Task<byte[]> MyTask(byte[] my_sent_data, CancellationToken cancelToken)
{
await Task.Delay(200, cancelToken);//??? What should happen here?
//Some code
}
Button event for canceling task and then closing the port:
private void Button_Disconnect_Click(object sender, RoutedEventArgs e)
{
my_cancelationTokenSource.Cancel();
if (my_port.IsOpen)
{
my_port.Close();
}
}
How can this code be optimized for stability?(i.e. port should only be closed after task is cancelled)
The solution here is to not close the port directly from the Disconnect button. Instead, cancel the token, and catch OperationCanceledException in MyMethod:
private CancellationTokenSource my_cancelationTokenSource;
private async void MyMethod()
{
my_cancelationTokenSource = new CancellationTokenSource();
try
{
while (true)
{
await Task.Delay(1000, my_cancelationTokenSource.Token);
//Process some code
byte[] my_received_data = await MyTask(my_sent_data, my_cancelationTokenSource.Token);
MyProgressMethod(my_received_data, my_sent_data);
}
}
catch (OperationCanceledException)
{
try
{
my_cancelationTokenSource.Dispose();
my_cancelationTokenSource = null;
my_port.Dispose();
}
catch { }
}
}
private void Button_Disconnect_Click(object sender, RoutedEventArgs e)
{
my_cancelationTokenSource?.Cancel();
}
Notes:
my_cancelationTokenSource becomes a field rather than a local variable.
Pass the token to the Task.Delay functions also. (It's unclear why you need the delays, normally you just wait for a response on the port).
I don't know what exactly you want done on cancellation, I'll leave that to you.
try/catch the closure of the port, which you should do via Dispose, just in case it throws.
I am using a EventWaitHandle() handler. This handler is called in a ButtonClick event that waits for 10 seconds. There is another worker thread which upon receiving some data call Set() on the handler.
Problem is the WaitOne() returns false after the timeout occurs. The worker thread doesnt run and looks like its suspended, hence Set() is not called. Once the timeout is over, my worker thread resumes and Set() method is called.
To verify I tried without the EventWaitHandle() to check if my worker thread actually takes 10 seconds of time, but it didnt, and Set() method had hit immediately.
I am not sure why the worker thread runs after the timeout has occurred in the
I am new to C#. Thanks in advance
MainWindow.xaml.cs
public static EventWaitHandle autoResetEvent = new EventWaitHandle(false, EventResetMode.AutoReset);
XYZDialogBox.cs
private void BtnConnect_Click(object sender, RoutedEventArgs e)
{
MainWindow.autoResetEvent.Reset();
if (!MainWindow.autoResetEvent.WaitOne(10000))
{
//Line number details is not received from Service
MessageBox.Show("Timeout");
//now disconnect and exit
strCommand = "#cmddisconnect " + tbIPAddress.Text + " #";
tcpClient.AddCommandAsync(strCommand);
return;
}
}
ABC.cs
public void ABC(ref string strData)
{
while(strData != "")
{
//do something
MainWindow.autoResetEvent.Set();
}
}
Using the async await pattern based on your code:
private async void BtnConnect_Click(object sender, RoutedEventArgs e)
{
// await frees up the main thread but halts execution of this method until finished.
var result = await Task.Run(() =>
{
//Do something that takes time.
// This is now in another thread.
return MyService.ServiceCall(arg);
});
// use result here synchronously.
}
As an aside the example here is very rudimentary case of using the async await pattern. Ideally your service would have a library that implements an async method call that returns an awaitable task. That would look something like this.
private async void BtnConnect_Click(object sender, RoutedEventArgs e)
{
bool success = await MyService.ServiceCallAsync(args); // async service call.
if(success)
{
// handle
return;
}
// an error occurred.
}
I have a form that shows a data grid. I also have a method running on a different thread that updates only the displayed cells of the grid. To do this, this method calls a function on the form that returns the displayed cells.
The problem I have is that sometimes while the form has been closed and disposed the method on the other thread is still calling this function which results in an objectdisposed exception. Is there a way (other then making sure the methode on the other thread is finished) to prevent this?
So I need a thread safe method to kill the background task when the form is closed.
private delegate List<foo> GetShownCellsDelegate();
public List<foo> GetShownCells()
{
if (this.InvokeRequired)
{
GetShownCellsDelegate getShownCellsDelegate = new GetShownCellsDelegate(GetShownCells);
return (List<foo>)this.Invoke(getShownCellsDelegate);
}
else
{
//do stuff
}
}
I tries using the IsDisposed property of the form:
if (!IsDisposed)
{
return (List<foo>)this.Invoke(getShownCellsDelegate);
}
But apparently the form can be dispossed after the if statement because I still get the isdisposed exception.
This is how I use the function on the other thread:
private CancellationTokenSource cts = new CancellationTokenSource();
public void CancelUpdate()
{
cts.Cancel();
}
public void ReadDataFromDevice()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ReadAllDataThreadPoolMethod));
}
private void ReadAllDataThreadPoolMethod(Object stateInfo)
{
if (!cts.IsCancellationRequested)
{
//do stuff
}
}
The CancelUpdate method is called from the IsClosing event on the form. But I still get the isdisposed exception sometimes.
To cancel the long running operation you can use a CancellationToken, which is specifically designed for cooperative cancellation.
Have the main form create a CancellationTokenSource when starting the background thread, pass the CacellationToken generated by the CTS to the backround thread, cancel the CTS when your form closes, and then have the background thread check the token to see if it is cancelled before trying to invoke back to the main thread.
public void Foo()
{
var cts = new CancellationTokenSource();
var task = Task.Run(() => DoWork(cts.Token));
FormClosing += (s, args) =>
{
cts.Cancel();
if (!task.IsCompleted)
{
args.Cancel = true;
task.ContinueWith(t => Close());
}
};
}
private void DoWork(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
//Do some work
}
}
To be absolutely sure that the background thread doesn't pass the cancellation check, then yield to the UI thread to have it cancel the token and dispose of the form, before the work is done, you'll also need to ensure that the background thread has time to run to completion after being cancelled, before the form closes. This can be done through a simple Thread.Join call in the closing handler.
this.FormClosed += new FormClosedEventHandler(form1_FormClosed);
void form1_FormClosed(object sender, FormClosedEventArgs e)
{
//close thread
}
This will be executed whenever your form is being closed.
I have a long running task that behaves like a transaction - it involves many operations where success of one depends on success of another.
class MyTransaction
{
public void Execute()
{
StopServices();
BackupFiles();
OverwriteFiles();
BackupDatabases();
RunChangeScripts();
... and few others
}
public void RollBack() { }
}
class MyTransactionManager
{
public RunTransactions()
{
Task.Factory.StartNew(() => {
new MyTransaction().Execute();
});
}
}
This is just a pseudo-code of the real application where different operations are provided by different components of the system. There is an underlying GUI (WinForms) that displays progress using a progress bar and few other thing that have to stay responsive no matter what happens. Transactions are all really long running so there is no need to specify it when starting tasks (using TaskCreationOptions), it always runs in a new thread. Progress from transactions is reported back to the GUI using events.
Now, there is a request that if something during execution of a transaction fails it won't immediately roll back as it currently does. They want to pop up a message box in the GUI giving a user an option to decide whether to roll back or fix the error and continue from the last successful point.
So I need somehow implement a blocking. I thought that I could just raise another event, pop up a message box and say "Hey, fix it and then press ok". And bind that OK click event to my outer manager (public API) which can delegate requests directly to my transactions. And blocking would just actively run a while loop checking some bool property.
Now I am thinking that passive blocking would be better but I don't really know how to do it. Could you please advise me?
EDIT: And I don't really want to use Thread.Sleep, because these errors can take various time to fix. Depends on an error and a person who is fixing it.
And blocking would just actively run a while loop checking some bool property.
That's not blocking, it's called busy waiting and it's something you should avoid.
If you want to have synchronization like this between two threads, one way is to use ManualResetEvent:
AskUser(); // doesn't block
shouldRollbackEvent.WaitOne();
if (shouldRollback) …
And on your UI thread:
shouldRollback = …;
shouldRollbackEvent.Set();
(This assumes both parts of the code execute within the same object.)
May be you can try something like this
private static Task<bool> WaitTillUserInput()
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
uiSynchronizationContext.Post(x =>
{
if (MessageBox.Show("Do you want to rollback...?", "Please confirm", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
tcs.SetResult(true);
}
else
{
tcs.SetResult(false);
}
}, null);
return tcs.Task;
}
C# 5.0
public async void Execute()
{
...Do something
//Encountered an error
var doRollBack = await WaitTillUserInput();
if(doRollBack)
{
//rollback here
}
}
C# 4.0
public void Execute()
{
...Do something
//Encountered an error
var doRollBackTask = WaitTillUserInput();
doRollBackTask.ContinueWith(antecedent =>
{
if (antecedent.Result)
{
//rollback here
}
});
}
EventWaitHandle _wait;
private async void buttonStart_Click(object sender, EventArgs e) {
_wait = new EventWaitHandle(true, EventResetMode.ManualReset);
await Task.Run(() => GoInc());
}
private void buttonPause_Click(object sender, EventArgs e) {
_wait.Reset();
}
private void buttonResume_Click(object sender, EventArgs e) {
_wait.Set();
}
EventWaitHandle _wait;
private void GoInc() {
for (int i = 0; i < 10000; i++) {
_wait.WaitOne();
Thread.Sleep(100);
}
}
I need to run an infinite while loop when a form application starts. A form starts like this:
public Form1()
{
InitializeComponent();
}
Now I want to run another function which will have an infinite loop inside with one second sleep time:
public void doProcess(){
while(true){
Thread.Sleep(1000);
// other task
}
}
How can I do this? When I call doProcess() in the constructor, it does not show the form. I tried to run the while loop for 10 iterations. The form showed up only after all the iterations are finished. I don't understand why it is happening.
You can start a new thread like this:
new Thread(() =>
{
while (true)
{
Thread.Sleep(1000);
//other tasks
}
}).Start();
Although I suggest you read up on threading before you do. If you want to update the form from a different thread you should use: Form.Invoke().
For example: w is the form
w.Invoke((MethodInvoker) delegate
{
w.Width += 100;
});
In short, you are blocking the UI Thread with this infinite loop.
Run it async:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
BeginWork();
}
private async void BeginWork()
{
while (true)
{
// Since we asynchronously wait, the UI thread is not blocked by the file download.
var result = await DoWork(formTextField.Text);
// Since we resume on the UI context, we can directly access UI elements.
formTextField.Text = result;
}
}
private async Task<string> DoWork(object text)
{
// Do actual work
await Task.Delay(1000);
// Return Actual Result
return DateTime.Now.Ticks.ToString();
}
}
A while(true) can be a bit excessive for an update loop. May I recommend that you potentially use a Timer, and/or leverage Cancellation Tokens to eagerly cancel requests which have taken too long as to not update UI with potentially stale results in high performance scenarios.
E.g.
public partial class Form1 : Form
{
private readonly Timer _sampleTimer;
public Form1()
{
InitializeComponent();
_sampleTimer = new Timer
{
Interval = 500 // 0.5 Seconds
};
_sampleTimer.Tick += DoWorkAndUpdateUIAsync;
}
private async void DoWorkAndUpdateUIAsync(object sender, EventArgs e)
{
// Since we asynchronously wait, the UI thread is not blocked by "the work".
var result = await DoWorkAsync();
// Since we resume on the UI context, we can directly access UI elements.
resultTextField.Text = result;
}
private async Task<string> DoWorkAsync()
{
await Task.Delay(1000); // Do actual work sampling usb async (not blocking ui)
return DateTime.Now.Ticks.ToString(); // Sample Result
}
private void startButton_Click(object sender, EventArgs e)
{
_sampleTimer.Start();
}
private void stopButton_Click(object sender, EventArgs e)
{
_sampleTimer.Stop();
}
}
It's happening because the ctor never exits and so the form cannot be shown - is this not obvious?
If you want to run a forever/sleep loop line this, you must thread it off.
Do not wait in GUI event handlers, (or ctors).
Can you not use forms.timer?
You are blocking the UI thread. Therefore, the UI cannot be processed as long as doProcess runs.
If you use .Net 4.5, you can use async waits:
public async void doProcess(){
while(true){
await Task.Delay(1000);
// other task
}
}
The cleaner solution would be to use a timer that fires an event every 1 second. You can turn off the timer after 10 loops.
You didn't exit the constructor so the form won't show.
If you want to do it after form shows place your code in Form_Load event.
But you rather want to do it using background thread so you can use backgroundworker
You could place it after the Initialize component, or find the load event of the form and paste your code in there