C# waiting for input from another thread using AutoResetEvent - c#

I spent some time searching for an answer to this and found plenty of helpful information in other threads. I believe I've written the code in a way that works, but I am not happy with the outcome.
I designed a piece of hardware that I am communicating with via C#. The hardware connects via USB and runs initialization routines after enumerating with the OS. At that point, it simply waits for the C# program to start sending commands. In my C# code, the user must press a "Connect" button, which sends a command and the required payload to let the hardware know it should continue running. The hardware then sends a command back as an ACK. The problem is that my C# program must wait to receive the ACK, but the GUI is totally frozen until the hardware responds as I don't know how to partition it out to another thread that can block freely. If the hardware responds immediately, then it works fine, but if it can't connect, then the program stays frozen indefinitely.
With that said, I know a few things need to happen, but I'm not sure how to implement them. First and foremost, I don't think sitting in a loop waiting on a boolean is the right way to go, but using AutoResetEvent doesn't really seem to be much better. There has to be a better way involving timers, more threads, or something similar.
I am using the DataReceived event with the serialPort object as follows:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
byte cmd = (byte)serialPort1.ReadByte();
if (cmd == (byte)Commands.USB_UART_CMD_MCU_CONNECT)
MCU_Connect_Received.Set();
}
In the buttonClick function ("main" thread), the program stops while it waits for the ACK:
//Send the command to signal a connection
Send_Connection_Packet((byte)Commands.USB_UART_CMD_PC_CONNECT);
textBox1.AppendText("-I- Attempting to contact hardware...");
MCU_Connect_Received.WaitOne();
textBox1.AppendText("Success!" + Environment.NewLine);
Ideally, I'd like to know if a timeout expired so I can print "Failed!" instead of "Success!". Not having a timeout also means it will sit there forever, as I mentioned above, until I kill the process. It's possible that it won't find any hardware, but if it does, it should respond in < 1 second, so a timeout of 2 seconds would be more than enough. I tried using Thread.Sleep, but that froze the GUI as well.

I recommend you use the Task class. You can use a TaskCompletionSource to complete the task when the operation completes.
Using the new async support, your code then becomes:
textBox1.AppendText("-I- Attempting to contact hardware...");
await Send_Connection_Packet((byte)Commands.USB_UART_CMD_PC_CONNECT);
textBox1.AppendText("Success!" + Environment.NewLine);
If you don't want to use the Async CTP, then you can call Task.ContinueWith and pass TaskScheduler.FromCurrentSynchronizationContext to schedule the textBox1.AppendText("Success!") line to run on the UI thread.
The async support also includes timers (TaskEx.Delay) and combinators (TaskEx.WhenAny), so you can easily check for timeouts:
textBox1.AppendText("-I- Attempting to contact hardware...");
var commTask = Send_Connection_Packet((byte)Commands.USB_UART_CMD_PC_CONNECT);
var timeoutTask = TaskEx.Delay(1000);
var completedTask = TaskEx.WhenAny(commTask, timeoutTask);
if (completedTask == commTask)
textBox1.AppendText("Success!" + Environment.NewLine);
else
textBox1.AppendText("Timeout :(" + Environment.NewLine);

The issue with the GUI freezing is because all the callbacks for GUI events occur in the thread that's running the GUI. If you don't want the GUI to freeze you need to spawn a new thread.
For implementing the timeout, you can do a timed wait on an event handle and then check the return value for true or false to determine if the call was successful or if it timed out.

To enable timeouts use another overload of WaitOne():
bool succeeded = MCU_Connect_Received.WaitOne(timeOutInMilliseconds, false);
if (succeeded)
{
textBox1.AppendText("Success!" + Environment.NewLine);
}
else
{
textBox1.AppendText("Failed!" + Environment.NewLine);
}
Consider moving communication-related code in a separate class to encapsulate the communication protocol. This way the code will be easier to maintain and you will able to implement all Task/background worker ideas the other people suggested.

If you want the GUI to remain responsive, you should run things in a background thread. A BackgroundWorker does this nicely. I'd stick with the resetevent over a busy wait construction. You can use a timer to trigger the resetevent after a timeout period

Related

How would I use Background Worker to get my GUI to respond?

I made a short program which has just a button. When the button is pressed, functionA is executed, which also uses functionB and functionC. Inside functionA is a loop which executes functionB and functionC X amount of times. At the end of each loop, the progressbar gets incremented by 1. At the beginning of functionA, before the loop, there's a webservice which pulls data from a website, and passes that onto B and C for processing (data file manipulation and saving to disk).
My problem is that everything works fine, but while functionA is still running, the GUI is stuck, so I can't close/minimize/drag the window around, I have to wait until A is done. I researched and they say I should use BackgroundWorker, but as being a new programmer, I've no idea on how to use it. Can someone give me a simple way to use it?
The progressbar loads fine, but it's just that while the function is running, the whole window is frozen, and I want it so I can move the window around, etc while the program is running, instead of waiting until the function is complete.
Thank you!
Call your function asynchronously like the following and it will not freeze the UI.
private async void BeginProcessingAsync(Data d)
{
//Execute the long running task asynchronously
await Task.Run(() => functionA(d));
//Anything after the await line will be executed only after the task is finished.
anotherFunction(d); // if you have one..
}
To run your task, simply call BeginProcessingAsync(d);. Also, please note: If you're using newer versions of .NET, you might have to use await Task.Factory.StartNew(() => functionA(d)); instead of the above
Overall, you'll want to make sure your GUI doesn't get updated from another thread. Instead, the messages should go to a threadsafe location. For instance, you could have the thread building into something like a database and have the GUI using a timer to look for updated data flags.
There is a question with a lot more detail using delegates here.
Marc's answer was the simplest and best, in my opinion:
///...blah blah updating files
string newText = "abc"; // running on worker thread
this.Invoke((MethodInvoker)delegate {
someLabel.Text = newText; // runs on UI thread
});
///...blah blah more updating files
From Dotnet Perls:
A Background Worker makes threads easy to implement in Windows
Forms. Intensive tasks need to be done on another thread so the UI
does not freeze. It is necessary to post messages and update the user
interface when the task is done.
Also, from MSDN, look at Task-based Asynchronous Pattern (TAP) if you're using C# 5.
The Task-based Asynchronous Pattern (TAP) is based on the
System.Threading.Tasks.Task and System.Threading.Tasks.Task
types in the System.Threading.Tasks namespace, which are used to
represent arbitrary asynchronous operations. TAP is the recommended
asynchronous design pattern for new development.

Application Freeze in loop when using Sleep

I have an application that I made to connect to a device using telnet, the application freeze/crash when I started it .. I have System.Threading.Thread.Sleep(3000); in couple locations of the application. I was wondering, is there a way to have the application active and buttons are useable but the some operations are only impacted by the sleep operation?
Thanks in advance.
Don't use Thread.Sleep, especially on the UI thread. This will cause a hang - by design.
Since you're using .NET 4.5, you can use await Task.Delay(3000); to asynchronously "sleep", which won't block the UI. However, this is typically a sign of a poor design - "waiting" is something that really shouldn't need to happen in a UI application in general. There are typically better approaches, such as using await on the asynchronous operation for which you're waiting, etc.
This requires a bit of an explanation. There are some threads that are special in this case the ui thread where the rendering of your Ui happens and the events from the input devices are handled. If this thread spends time doing any calculations windows will state that your application has frozen. Since you are using Thread.Sleep on it you get this result.
Articles to understand the problem
http://msdn.microsoft.com/en-us/library/ms741870(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/dd744765(v=vs.85).aspx
Recommended Solutions
On the Button press dispatch a thread that goes and does the work that you need to happen. On the meantime change the cursor for the mouse to indicate that work is happening or show a progress bar. Once it finishes you can fire(dispatchet) an event that changes the ui.
I would do something similar to:
// The Work to perform on another thread
ThreadStart start = delegate() { // ... // This will work as its using the dispatcher
DispatcherOperation op = Dispatcher.BeginInvoke( DispatcherPriority.Normal, new Action<string>(SetStatus),
"From Other Thread (Async)");
DispatcherOperationStatus status = op.Status; while (status != DispatcherOperationStatus.Completed) { status = op.Wait(TimeSpan.FromMilliseconds(1000));
if (status == DispatcherOperationStatus.Aborted)
{ // Alert Someone } } }; // Create the thread and kick it started! new
Thread(start).Start();
More Examples at:
http://msdn.microsoft.com/en-us/magazine/cc163328.aspx
If you are calling sleep within your application it will do just that. If you do not want your application to hang, you will need to create a new thread that does whatever monitoring and waiting you want it to do, if a particular condition you are looking for is met, then use a callback to your parent thread to perform whatever task you want to do.

What's a good way to implement a "stop/cancel" button to stop a thread (that ins't a background worker)

I've got a WPF application that does a lot of talking to a remote server, so to keep the UI nice and responsive I put those operations in a second thread. There are a few possible, though unlikely, instances where that thread would just hang, blocking forever. Is there a simple way for me to implement a "cancel" button that doesn't involve calling thread.Abort()? I see a lot of people advise against using that, and I don't want to leave any unreleased resources. Perhaps a way to force the thread to throw an exception?
I specify in the title that this isn't a background worker because the program doesn't use those. It's already coded up with plain old threads.
I absolutely agree with comments that you need to fix what's broken, because that's the real issue, but if you can't at the moment, and need to continue operating. If you are on .Net 4.0, use the Task library. You can create a task and pass it an action that will execute on a different thread. The key is that you can pass a cancellation token to that task.
http://msdn.microsoft.com/en-us/library/dd997396.aspx
if you fire the same action over and over, you can also check the task status and do something about that.
//this is just a sample
if (myTask != null) //meaning it's still exe'ing your action
{
if (myTask.Status == TaskStatus.Faulted) //there's some kind of a problem with exe'ing it
myTask = null; // could reset to run the action again
else
return; //let the task finish
}
myTask = Task.Factory.StartNew (() =>
{
ExecuteUMyAction ();
});

How to unblock ConnectNamedPipe and ReadFile? [C#]

I have a class (NamedPipeManager) which has a thread (PipeThread) that waits for a NamedPipe connection using (ConnectNamedPipe) and then reads (ReadFile) - these are blocking calls (not-overlapped) - however there comes a point when I want to unblock them - for example when the calling class tries to stop the NamedPipeManager...
How can I interupt it? Using Thread.abort? Thread.interrupt? Is there a proper way to handle this?
Refer to the code below which illustrates my current situation
main()
{
NamedPipeManager np = new NamedPipeManager();
... do stuff ...
... do stuff ...
np.Stop(); // at this point I want to stop waiting on a connection
}
class NamedPipeManager
{
private Thread PipeThread;
public NamedPipeManager
{
PipeThread = new Thread(new ThreadStart(ManagePipes));
PipeThread.IsBackground = true;
PipeThread.Name = "NamedPipe Manager";
PipeThread.Start();
}
private void ManagePipes()
{
handle = CreateNamedPipe(..., PIPE_WAIT, ...);
ConnectNamedPipe(handle, null); // this is the BLOCKING call waiting for client connection
ReadFile(....); // this is the BLOCKING call to readfile after a connection has been established
}
public void Stop()
{
/// This is where I need to do my magic
/// But somehow I need to stop PipeThread
PipeThread.abort(); //?? my gut tells me this is bad
}
};
So, in function Stop() - how would I gracefully unblock the call to ConnectNamedPipe(...) or ReadFile(...)?
Any help would be appreciated.
Thanks,
It seems to be working on VC6.0, WinXP if I try to interrupt ConnectNamedPipe by
DeleteFile("\\\\.\\pipe\\yourpipehere");
So just specify name, not handle.
Starting with Windows Vista, there is a CancelSynchronousIO operation available for threads. I don't think there is a C# wrapper for it, so you would need to use PInvoke to call it.
Before Vista, there isn't really a way to perform such an operation gracefully. I would advise against using thread cancellation (which might work, but doesn't qualify as graceful). Your best approach is to use overlapped IO.
Recently I was in a situation, I could not use the Async Overlapped IO. I was stuck on the server side within ConnectNamedPipe. To unlock the thread and free resources, I had to connect to the same pipe as a client for a split second.
Main thread receives the stop signal
Main thread sets the stop event for the listening thread
Main thread connects to the pipe
If succeeded (always) - closes the newly created handle immediately
Listener thread unlocks
Listener thread does whatever required
This worked for me very well.
To unblock ReadFile one needs to connect and write to the pipe. Same effect epected.

Creating a Loop to Pause a Script While a Callback Function Operates

I am currently using a third party component to handle telnet connections in .NET. I want it to be synchronous where I send a command to the receiving telnet server and then I get the response back as text or byte array. Only problem is that the component is not set up to do that. The component allows me to send commands to the server, but the response is returned via a function handle. So in essence, I need a way to pause the application while the handler does it's processing. Here is an example of how I plan to get around that issue:
static void Main(string[] args)
{
Telnet telCon = new Telnet();
telCon.OnDataIn += new Telnet.OnDataInHandler(HandleDataIn);
telCon.Connect(remoteHostStr);
while (true) ;
}
public static void HandleDataIn(object sender, TelnetDataInEventArgs e)
{
string responseStr = e.Text;
if (responseStr.Contains("Username:"))
{
((Telnet)sender).Send(System.Text.ASCIIEncoding.ASCII.GetBytes(username));
}
else if (responseStr.Contains("Password:"))
{
((Telnet)sender).Send(System.Text.ASCIIEncoding.ASCII.GetBytes(password));
}
}
The solution above will not work since the while will always run, but I will probably build a future version that uses some sort of global variable to track if the loop still needs to run. However, everything I have been taught about programming says this is very dirty. Can anyone think of another way around my dilemma?
Thanks,
Chris
Here is an example of using a ManualResetEvent to suspend execution (and delay program end) until your event handler says it's finished.
static ManualResetEvent finishGate;
static void Main(string[] args)
{
finishGate = new ManualResetEvent(false); // initial state unsignaled
Telnet telCon = new Telnet();
telCon.OnDataIn += new Telnet.OnDataInHandler(HandleDataIn);
telCon.Connect(remoteHostStr);
finishGate.WaitOne(); // waits until the gate is signaled
}
public static void HandleDataIn(object sender, TelnetDataInEventArgs e)
{
// handle event
if (processingComplete)
finishGate.Set(); // signals the gate
}
The WaitOne() method of ManualResetEvent also includes overrides that accept a timespan or number of milliseconds. It returns bool - true if it was signaled, false if it timed out. If you put that in a loop, you could have your main thread wake up every 30 seconds and perform some housekeeping tasks, but still have an instantaneous response when the gate is signaled.
Your while loop:
while(true) ;
will drive CPU usage to 100% (well, 100% of 1 core on a multicore machine) and leave it there, permanently.
This will starve other processes of CPU power, and may prevent the Telnet component from working at all because you've bypassed the message pump.
There are better ways, but without more information on what you're doing, it will be hard to advise you.
To begin, do you want a WindowsForms/WPF/Console application?
[And please, use comments to answer, not Answers.]
In general, when you really need to wait, use a WaitHandle. In this case, a ManualResetEvent would probably be what you need.
A better way would be to spawn the Telnet processing to another thread. That way you can get the main thread to wait for the telnet processing to complete.
Have a look here for some very good tutorials on threading.

Categories