I have an issue when there is an exception in a block of code that uses a lock. I am reading and writing to a serial port and there are several different threads that need access to the same serial port. This is managed by a lock. I have no issues except if the serial port stops working. This can happen since the software controls an RF transmitter and occasionally the rf can cause usb to serial ports to stop functioning. If you then attempt to write to the port you will get a write timeout. I tried handling this from a try - catch exception handler. However, the program locks hard at that point and has to have the task killed. I am not sure if this is coming from the exception or the message box I am trying to display since it could result from a background thread. Here is the code:
lock (_object)
{
try
{
if (portOpened)
{
port.Write(data);
}
else
{
MessageBox.Show("The radio is not connected. Please select a ComPort in the settings dialog");
}
}
catch (Exception x) //this will capture a write exception.
{
MessageBox.Show("The program is unable to write to the serial port. Select OK to close the program";
Application.Exit();
}
finally
{
}
}
Thanks for any help
If you want to force to exit the app, Application.Exit is not a good candidate, as it simply pushes the Close request on message queues of all threads, but does not force anything. If you want to stop app at any cost, use Environment.Exit(exitCode), or may be even better Environment.FailFast, with specified exception so it will be logged into the system's log: convenient for future investigations.
Related
I'm writing a C# program that sends some simple commands to Arduino. via USB serial virtual port.
Sometimes happen that the program hangs, even if the code is protected by a try/catch block.
When I saw the problem the problem seem to be in closing the port.
The function is very simple:
void Send() {
try {
Debug.WriteLine("SR1 "+rel+" "+status);
_serialArduino.Open();
Debug.WriteLine("SR2");
_serialArduino.WriteLine(string.Format("switch {0} {1}\n", rel, Convert.ToSByte(status)));
Debug.WriteLine("SR3 '"+_serialArduino.ReadLine()+"'");
_serialArduino.Close();
Debug.WriteLine("SR4");
Thread.Sleep(400);
} catch (Exception e) {
LogManager.Write(string.Format("ERR SwitchRel({0}, {1}) - {2}", rel, status, e.Message));
}
}
I read about a problem during the Close function but in this case no DataReceived event handler is defined (==null).
Any idea?
* Edited to add some details *
After days of debugging and log analysis I discovered the following:
I'm working on a device running Win7Embedded Standard
The application is written in C#
after some time (or maybe caused from something unknown, so far) the port connecting Arduino disappeared from the list of the enumerated ports
the program initially reports on my log 'Device disconnected' and then 'Port COM9 does not exist' messages
The device manager reports COM9 on the 'Ports' tree (!!)
If I shut the program and re-run it, it reports 'COM9 does not exist' and if I list the ports the COM9 does not appear
My guess is that the usbser driver is in a mess.
The only solution, so far, is reset the board.
Is there a way to reset the driver without reboot and check if it returns in a known state?
Or maybe is the DotNet Framework that does not detect the port ?
I am developing a C# WinForms Windows application that runs from the tray. I need to provide some reasonable level of error handling and instruction to the user. In order to test if I am able to open a serial port for communication, I wish to have a way to test if it is already open or if it is unopenable for whatever reason.
I came up with this:
if (SerialPort.GetPortNames().Select((n) =>
n.ToUpperInvariant()).Contains(mycomportname))
{
// Port found, check to see if we can use it by test-opening
using (var sp = new SerialPort(mycomportname))
{
// Check to see if we can open this port
try
{
if (sp.IsOpen) throw new Exception("Serial port is already open");
sp.Open();
sp.Close();
}
catch (Exception ex)
{
throw new Exception("Serial port is in use");
}
}
}
else
{
// ...
}
commManager.PortName = mycomportname;
if (commManager.OpenPort())
{
// .. always returns false because causes UnauthorizedAccessException on open
}
For some reason the serial port does not seem to be fully released by the 'using' statement. The UnauthorizedAccessException does not occur when I delete the using statement and the statements inside it. How do I write robust error-tolerant serial port opening code?
The MSDN article for SerialPort warns about this explicitly, albeit vaguely. SerialPort uses a worker thread to generate events like DataReceived and ErrorReceived. That thread gets started when you call Open() but it needs time to exit again after you call Close() or Dispose(). The physical port is in use until that happens. Exactly how long that takes is unpredictable. Usually within a millisecond but the worst-case is seconds when the machine is heavily loaded. Your code only waits for a nanosecond so you'll always get an exception.
The approach otherwise just doesn't make sense. Once you opened the port and got no exception then just keep it open. No point in closing it again and reopening it. Which is the simple solution.
And never do this kind of port scanning when GetPortNames() returns more than one port. The odds that the first one will open are very high, the odds that it is the right one are low. Murphy ensures that fifty-fifty odds turn into 1%. You always need to provide a config file so the user can pick the correct one. Only consider doing the port scanning when you populate a combobox with choices in a config helper window. Only skimp on this if you are in control over the machine configuration, that's pretty rare.
I am having stability issues using a named pipe for communication between a C# and Java app.
Here is the code that sets up the named pipe in C# and reads lines of XML strings.
try
{
NamedPipeServerStream inStream = new NamedPipeServerStream(inName, PipeDirection.In);
inStream.WaitForConnection();
reader = new StreamReader(inStream);
while (!Stopped && !reader.EndOfStream)
{
string xml = reader.ReadLine();
processXml(xml);
}
}
catch (Exception e)
{
log.Error("Error in receiver", e);
}
finally
{
log.Info("Receiver ended");
}
And here is the connection and write code in Java
public void connect() throws TransportUnavailableException
{
try
{
File inPipe = new File(inName);
os = new FileOutputStream(inPipe);
// Uses JAXB for XML serialization
marshaller = context.createMarshaller();
}
catch (FileNotFoundException e)
{
throw new TransportUnavailableException("Named pipe not found: " + inName);
}
}
public void send(Message message)
{
marshaller.marshal(message, os);
os.write('\n');
os.flush();
}
Everything works fine normally. But many users are reporting crashes. I don't see any exceptions in logs that suggest a reason for the pipe dying. I just see that the receiving thread in C# ends (i.e. 'Receiver ended' in the logs) and after this I get an IO exception on the next attempted send from Java with a message 'The handle is invalid'. This seems to happen randomly, but usually within the 1st minute or 2 after the connection was established. The pipe ending message also happens when the application is not doing anything, it could have been minutes since the last user operation. Then it could be a few more minutes before the next write is attempted from Java.
All reasons for my app to bring down the pipe on purpose (e.g. a crash elsewhere in system) are logged and I never see that as a reason for the pipe ended, I just get the message that the reader has given up reading.
Could there be any external reason for the pipe being killed, anti-virus, firewall etc?
I noticed I didn't use a RandomAccessFile from Java like most examples seem to use. Could this be a reason?
Any help/suggestion appreciated
Thanks!
Your server side code only processes one connection, then it exits when it reads to EOS. You need to create the named pipe, loop accepting connections, and spin up a new thread to handle each connection. You also need to close each connection when you're finished with it.
However I would use TCP rather than named pipes for this, for several reasons.
To start I am coding in C#. I am writing data of varying sizes to a device through a socket. After writing the data I want to read from the socket because the device will write back an error code/completion message once it has finished processing all of the data. Currently I have something like this:
byte[] resultErrorCode = new byte[1];
resultErrorCode[0] = 255;
while (resultErrorCode[0] == 255)
{
try
{
ReadFromSocket(ref resultErrorCode);
}
catch (Exception)
{
}
}
Console.WriteLine(ErrorList[resultErrorCode[0] - 48]);
I use ReadFromSocket in other places, so I know that it is working correctly. What ends up happening is that the port I am connecting from (on my machine) changes to random ports. I think that this causes the firmware on the other side to have a bad connection. So when I write data on the other side, it tries to write data to the original port that I connected through, but after trying to read several times, the connection port changes on my side.
How can I read from the socket continuously until I receive a completion command? If I know that something is wrong with the loop because for my smallest test file it takes 1 min and 13 seconds pretty consistently. I have tested the code by removing the loop and putting the code to sleep for 1 min and 15 seconds. When it resumes, it successfully reads the completion command that I am expecting. Does anyone have any advice?
What you should have is a separate thread which will act like a driver of your external hardware. This thread will receive all data, parse it and transmit the appropriate messages to the rest of your application. This portion of code will give you an idea of how receive and parse data from your hardware.
public void ContinuousReceive(){
byte[] buffer = new byte[1024];
bool terminationCodeReceived = false;
while(!terminationCodeReceived){
try{
if(server.Receive(buffer)>0){
// We got something
// Parse the received data and check if the termination code
// is received or not
}
}catch (SocketException e){
Console.WriteLine("Oops! Something bad happened:" + e.Message);
}
}
}
Notes:
If you want to open a specific port on your machine (some external hardware are configured to talk to a predefined port) then you should specify that when you create your socket
Never close your socket until you want to stop your application or the external hardware API requires that. Keeping your socket open will resolve the random port change
using Thread.Sleep when dealing with external hardware is not a good idea. When possible, you should either use events (in case of RS232 connections) or blocking calls on separate threads as it is the case in the code above.
Occasionally some of my integration tests are failing with the above message. I'm using the code below to ready the port.
for(int i = 0; i < 5; i++)
{
try
{
port.Open();
if (port.IsOpen)
break;
}
catch (Exception e)
{
try
{
port.Close();
}
catch (Exception)
{}
Thread.Sleep(300);
}
}
My assumption is that because it can't be the current thread blocking the port (because it will try to close it), it must be another thread or process that has died without cleaning up properly (one of the other tests - nothing else accesses this port). Is there a way to reset the state of the SerialPort so that the new thread / process can access it again?
Thanks,
Richard
This is a flaw in the SerialPort class, it uses an internal helper thread to wait for events on the port. The source of the DataReceived, PinChanged and ErrorReceived events. The flaw is in the Close() method implementation, it doesn't wait for this helper thread to terminate. That takes time, the exact amount of time is not predictable and could be many seconds when the machine is particularly busy. The physical port doesn't get closed until this happens, opening the port before the thread exits bombs with a 'port already in use' exception. The one you get. Sleeping for 300 msec is thus not good enough.
This is not normally an issue, serial ports are not sharable devices. Closing a serial port and not exiting your program is dangerous, another process could steal the port. Also giving you this exception when you try to open it again. The normal practice is to open the port when your app starts and not close it until it terminates.
I routinely verify that the port is closed just before I instantiate a serial port. This helps if you stop debugging code without closing the serial port. Also you should wait 250 msec after opening or closing the port before you continue with your code.
try
{
if (m_SerialPort != null)
{
if (m_SerialPort.IsOpen)
{
m_SerialPort.Close();
}
}
m_SerialPort = new SerialPort(portName, dataRate, parity, databits, stopBits.One);
m_SerialPort.Open();
if (!m_SerialPort.IsOpen)
{
MessageBox.Show(string.Concat(portName, " failed to open"));
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
I can't see where you close the port.
The issue for me is not here (even if you should refactor a bit the code) but probably you are calling port.Open(); when the port is still open
From MSDN
Only one open connection can exist per SerialPort object.
(I can't tell you why because I don't have enough information) Bear also in mind the the close method takes some time to actually close the port in fact you should block the main thread until the port has been close (perhaps using Thread.Join)
From MSDN
The best practice for any application is to wait for some amount of time after calling the Close method before attempting to call the Open method, as the port may not be closed instantly.
for more info
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.open.aspx
GC.SuppressFinalize should be called passing the SerialPort instance BaseStream property as the parameter and not just the SerialPort instance.
public class SerialConnection : SerialPort
{
public new void Dispose()
{
if (_isDisposed)
return;
_isDisposed = true;
BaseStream.Dispose();
GC.SuppressFinalize(BaseStream);
base.Dispose();
GC.SuppressFinalize(this);
}
The new void Dispose() of course is not the recommended way to implement IDisposable. It's merely a fix for the odd behaviour of the SerialPort class.