I am developing a .NET 4.0 WPF application in C# that controls a motor via RS232. I am having problems when exiting my application that the application sometimes deadlocks when closing the comport.
After some research on the internet I noticed this was a common problem and that using BeginInvoke in the DataReceivedEvent or closing the serialport in a different thread should solve the problem.
The problem with those workarounds are that.
1. I dont use the DataReceiveEvent.
2. closing the serialport in another thread doesnt make any difference. What happens is that the GUI shutsdown but you can see in the TaskManager that the process is still running.
Other things I have tried is:
Not closing the serialport and just exiting the application. This successfully closes the application and process but the serialport is still blocked, and to unblock the serialport I need to restart the computer.
Sleeping a couple of seconds before and after I close the serialport.
Having the application be a WinForms app. instead of WPF. No difference in the deadlock between the two.
The computer I run the program on uses com ports that are mounted on the motherboard and have Microsoft drivers.
And now for some code:
Window_Closing event looks like this:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
window.Closing -= Window_Closing;
Thread CloseDown = new Thread(new ThreadStart(server.Dispose)); //Closes serialport everything in another thread to avoid hang on serialport close.
CloseDown.Start();
}
Where server is the object that manages the serialport. And Dispose calls the serialport close function.
Serialport close function:
public void Close()
{
DebugLog.Write(3, "-->MacCommSerialPort.Close");
_com.Close();
DebugLog.Write(3, "<--MacCommSerialPort.Close");
}
Serialport settings:
_com = new SerialPort(portNumber);
_com.BaudRate = 19200;
_com.Parity = Parity.None;
_com.DataBits = 8;
_com.Encoding = Encoding.GetEncoding("Windows-1252");
_com.StopBits = StopBits.One;
_com.RtsEnable = false;
_com.DtrEnable = false;
_com.WriteTimeout = 400;
_com.ReadTimeout = 1000;
I just happened to look at your code and guess you should use the AutoThreadRest event before closing your GUI.
private static AutoResetEvent PortClosedEvent = new AutoResetEvent(false);
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
window.Closing -= Window_Closing;
Thread CloseDown = new Thread(new ThreadStart(server.Dispose));
CloseDown.Start();
PortClosedEvent.WaitOne();
}
and inside the server.Dispose method after you are done disposing the connection add this below line of code.
PortClosedEvent.Set();
I would check to make sure that the handshaking protocol between your application and the motor (i.e. sender and receiver) matches.
Related
Im trying to read data from a COM serial port, but the port is auto closing randomly, i dont know what to do, nowhere in my code i call the close method. i tried setup events on dispose, setup try catch and debug all catchs, but no luck.
Tried to create an infinity thread that when SerialPort.isOpen return false the thread reopen the serial port, it work but the thread eats the cpu at 100%..
Dont know what else to do...
The code that opens the serial
_serialPort.DataReceived += new SerialDataReceivedEventHandler(RecebendoDados);
_serialPort.Disposed += new EventHandler(PortaFechou);
_serialPort.ErrorReceived += new SerialErrorReceivedEventHandler(PortaErro);
_serialPort.PinChanged += new SerialPinChangedEventHandler(PinMudou);
_serialPort.Open();
PortIsOpen = _serialPort.IsOpen;
Why do you keep the COM port opened? Just open it when you write then close it!
Use this:
if (!serialPort1.IsOpen)
serialPort1.Open();
if (serialPort1.IsOpen)
{
serialPort1.WriteLine(inst.ToString());
serialPort1.Close();
}
i writed a program with Serial Port as this:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
serialLabel.BackColor = Color.Red;
storage = serialPort1.ReadExisting();
if (storage.Contains("CMGL"))
{
if (storage.Length > 65)
{
processUnreadedMessages(storage);
}
else
{
Thread.Sleep(500);
}
}
else if (storage.Contains("CMTI"))
{
serialPort1.Write("AT+CMGL\r");
Thread.Sleep(500);
}
storage = "";
serialLabel.BackColor = Color.Lime;
}
in visual studio when i run program works good!
but when i'l create setup for my program or run exe file, data don't receive to serialPort, and i don't get any error. but when i send data with this program it's work!
can you help Me?
the problematic lines are probably those:
serialLabel.BackColor = Color.Red;
and
serialLabel.BackColor = Color.Lime;
there's a slim chance it will still work in developent environment, but:
The DataReceived event is raised on a secondary thread when data is
received from the SerialPort object. Because this event is raised on a
secondary thread, and not the main thread, attempting to modify some
elements in the main thread, such as UI elements, could raise a
threading exception. If it is necessary to modify elements in the main
Form or Control, post change requests back using Invoke, which will do
the work on the proper thread.
[msdn]
try instead:
serialLabel.Invoke(new EventHandler(delegate
{
serialLabel.BackColor = Color.Red;
}));
Also:
make sure you don't touch GUI or anything that should be accessed from the thread it was created on without invoking (e.g. you also shouldn't write data to EventLog without Invoking) in your method processUnreadedMessages()
Check if there's no First Chance exceptions when you debug your application
check Application EventLog for messages generated by your application.
log data you received in serialPort1_DataReceived event to a file before you do anything else (this will check if DataReceived event is raised at all when it should)
subscribe to SerialPort.ErrorReceived event
So I have a socket server running, inside an asp.net ( C# ) application (very bad approach) that notifies any device connected,
It was like that when I started working at this company and changing it is not on a priority to my supervisors even though it will be better.
So what happens is when we do an update to the Website the Socket connection stays open (in another thread), then we have to restart the Server, but what I want to do is somehow get the Thread ID on startup of the Socket, then store it, if the update is done it should reattach to that thread and end the Socket somehow or reset it.
Is this possible?
this is sample code
private void Start()
{
_socketServer = new TcpListener(IPAddress.Any, Convert.ToInt32(ConfigurationManager.AppSettings["NotificationSocketPort"]));
_socketServer.Start();
_acceptingThread = new Thread(() =>
{
while (true)
{
try
{
var client = _socketServer.AcceptTcpClient();
StartClient(client);
}
catch (ObjectDisposedException ex)
{
_acceptingThread = null;
_socketServer = null;
Start();
break;
}
}
});
_acceptingThread.Start();
}
public void Close()
{
if (_acceptingThread != null)
{
_acceptingThread.Abort(0x0);
_socketServer.Stop();
_acceptingThread = null;
_socketServer = null;
}
}
In global.asax
protected void Application_End(object sender, EventArgs e)
{
SocketNotifier.GetNotifierInstance().Close();
}
The SocketNotifier is using the Singleton Design Pattern
Frankly, this is just the wrong approach. Web apps restart, and should be expected to restart. Sockets don't like that, and should not be expected to like that. Your best bet here would be to re-write the socket code as a windows service - that way it can keep running independently of the web-app.
They [the sockets] stay open that is the problem after IIS worker process terminates and a new one is started
Probably, IIS has trouble shutting down the old process. That keeps the socket open. Your socket thread is a foreground thread. It does not prevent process termination. Also, aborting a thread does not affect IO. And your socket listening method automatically restarts itself when the socket is closed.
Remove these problems. Make the thread a background thread. Don't abort it. Don't restart it in case of an ObjectDisposedException.
I have a C# program that reads from two serial ports at the same time. The serial port device is a Prolific USD to 4 serial ports adapter and I plug the two hardware on separate ports of the adapter. The problem is when I read from each port one at a time, everything works fine but when I try to read from both ports at the same time, one of the port is not responding. To troubleshoot the problem, I started two instances of the application and was able to read from the two ports at a time (one from each instance of the application). Does anyone know how to read from two separate serial ports in one application at the same time? Thank you.
Adding some codes:
Port 1:
// button to start or stop reading from port 1. Because the hardware requires me to write to it before reading the response, the writing is done in the timer
private void buttonPort1_Click(object sender, EventArgs e)
{
if (buttonPort1.Text == "Start Recording")
{
if (!port1.IsOpen)
{
port1.Open();
}
timerPort1.Start();
buttonPort1.Text = "Stop Recording";
}
else
{
timerPort1.Stop();
buttonPort1.Text = "Start Recording";
}
}
// Write "D" to the hardware each time to receive back the response
private void timerPort1_Tick(object sender, EventArgs e)
{
port1.Write("D");
}
void port1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
string result = port1.ReadLine();
oneParamDelegate dg = PHandCondResult; // send back the result to the main thread
this.Invoke(dg, result);
}
catch
{
}
}
Port 2
The code for the second port is similar to the above really, the difference being different port, datareceived event and timer.
I'll try the multiple thread options suggested by Grant Thomas: I didn't try this before because I thought serial ports are already working on separate threads: the datareceived event doesn't block the main thread and you can't access controls created on the main thread but I'll still give it a go using background worker and revert back later. Thank you all for the quick response.
You're going to need to do some reading, specifically on Threading.
If you have, say, some code that looks like this:
ReadDataFromSomePort();
ReadDataFromSomeOtherPort();
Then the first will execute synchronously (blocking) and then the latter. This happens on the same thread, the main application thread. When you want to do asynchronous things, including just doing one thing while keeping a UI interactive/responsive, then you need to delegate work to other threads.
So, you end up with something like this:
var thread1 = new Thread(ReadDataFromSomePort);
var thread2 = new Thread(ReadDataFromSomeOtherPort);
thread1.Start();
thread2.Start();
There's more to it than this, rest assured, so I recommend some research on the concept before proceeding.
MSDN has a tutorial/programming reference for threading that should get you started.
Creating two different objects of SerialPort and different DataReceived events for both should work.
I have an app where I read from the serialport, everything goes fine, until I close the app. When I click on the [X] the app simply hangs, the UI: unresponsive.
I read from the port in the DataReceived event handler, and I close the port when FormClosed happens:
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
{
mySerialPort.Close();
}
It's not a bug.
The only reason it would hang when you close it is because in the event handler of your SerialPort object, you're synchronizing a call with the main thread (typically by calling invoke). SerialPort's close method waits for its EventLoopRunner thread which fires DataReceived/Error/PinChanged events to terminate, but since your own code in the event is also waiting for main thread to respond, you run into a dead lock situation.
The reason the bug report was closed 'as designed' is because the 'bug' is in your own code.
Serial Port hangs while closing
This is a known issue with the SerialPort class and described in this Product Feedback article as well as several threads in these forums. You may notice the "closed by design" dismissal.
If your application is calling Invoke to process recevied data try calling BeginInvoke instead.
Instead of:
this.Invoke(d, new object[] { s, tb });
use:
this.BeginInvoke(d, new object[] { s, tb });
Simplest solution if you only want to close the port when the app closes, is to just not bother to Close() the port. The port will still get closed anyway when the app disposes of the serial port. The port will be available to be opened again by your app when it restarts, or by other apps that may wish to use the port.
this work very good :
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
if (_serialPort.IsOpen)
{
e.Cancel = true; //cancel the fom closing
Thread CloseDown = new Thread(new ThreadStart(CloseSerialOnExit)); //close port in new thread to avoid hang
CloseDown.Start(); //close port in new thread to avoid hang
}
}
private void CloseSerialOnExit()
{
try
{
_serialPort.Close(); //close the serial port
}
catch (Exception ex)
{
MessageBox.Show(ex.Message); //catch any serial port closing error messages
}
this.Invoke(new EventHandler(NowClose)); //now close back in the main thread
}
private void NowClose(object sender, EventArgs e)
{
this.Close(); //now close the form
}