I'm new to Windows development.
I've developed a WinForm application that communicate with a serial device and plot data on a chart.
The application should run 24h a day 7/7. The code is executed correctly, but after some hours of execution the UI freeze with a non responsive OS (I have to turn off the pc and restart it).
Serial class (using System.IO.Ports) execute read and write operations on separate thread.
This scenario make me think to a non correct cross-thread call from my serial class to UI. Reading Microsoft documentation and other questions i think i fixed the error but no way, the app continue to freeze the OS.
Write operation send a request character every 100ms to the board via serial, i'm using System.Threading.Timer to do that cause this operation will not interact with UI.
//Initialization
WriteTimer = new Timer(Write, COMport.IsOpen, 5000, 100);
// callback function
public static void Write(object state)
{
if ((bool) state)
{
try
{
COMport.Write("^");
}
catch (Exception exc)
{
ErrorLogger.WriteTxtLog(DateTime.Now,exc.ToString());
}
}
}
The serial board reply to the request char with a string of 10 bytes, to read the message I'm using the DataReceived event handler form IO.Ports, that is also execute on a separated thread, the received data will be elaborated and than passed to UI with a event handler delegate with args declared on the main form class. I pass the form control to the serial class to make a safe thread call.
// FormControl is passed in the constructor of the serial class:
public Form1 FormControl;
private void COMport_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort port = (SerialPort) sender;
byte[] buffer = new byte[10];
try
{
for (int i = 0; i < buffer.Length && buffer[i]!=3 ; i++)
{
buffer[i] = (byte) port.ReadByte();
}
SerialDataArgs args = checkDataReceived(buffer);
if (!args.error)
{
FormControl.Invoke(FormControl.drItem, new SerialDataArgs(...));
}
else
{
FormControl.Invoke(FormControl.drItem, new SerialDataArgs(0,0,true));
ErrorLogger.WriteTxtLog(DateTime.Now, "");
}
}
catch (Exception exc)
{
ErrorLogger.WriteTxtLog(DateTime.Now, exc.ToString());
}
}
UI thread (Form1 class):
SerialClass Serial = null;
public delegate void DataReceived(SerialDataArgs args);
public DataReceived drItem;
void ConnectCOM()
{
// COM READ
if (Serial == null)
{
Serial = new SerialClass(param.comName, this //this should be the FORM CONTROL);
if (Serial.Open)
{
...
drItem += HandleSeriaData;
}
else
{
...
}
}
}
//EventHandler
private void HandleSeriaData(SerialDataArgs args)
{
if (!args.error)
{
Work(args...); // in the work method i'll update labels, drawGraph,....
}
else
{
if (!Serial.Open) RecoverySerial();
}
}
Maybe the error is not here, but in front of Windows crashing it seems to me the only interested part. Sorry for my bad English, hope I made a correct/non duplicate question.
Use Control.BeginInvoke instead of Control.Invoke
From my experience, usually problems with System.IO.Ports.SerialPort cause only the UI to freeze, not the OS, and are caused by a deadlock when trying to update the UI from the SerialPort .DataReceived event using Control.Invoke and the UI thread itself tries to access the SerialPort object for example to close it. In this case there can be a deadlock when the UI thread is waiting for the SerialPort DataReceived thread to complete and the DataReceived thread is waiting for the UI thread to complete the Control.Invoke. To overcome these kinds of problems, it is better to use Control.BeginInvoke so the DataReceived thread does not wait for the UI thread.
Use lock to synchronize access to shared resources
When accessing the same object from different threads, use lock to synchronize data access. None synchronized data access can cause all different weird problems.
Check if the problem is with the serial port driver or connection
When the UI freezes and the OS becomes unresponsive, try to remove the serial-port device and see if the OS becomes responsive. If so, the problem may not be in the application but in the serial port driver or connection.
Hope this helps
Related
I'm working with a fingerprint sensor on Arduino, but sometimes, on runtime, my WPF app throws an exception on sp.Open() saying "COM3" Access denied"
Here's the code on c#:
public string ConfigPort()
{
SerialPort sp = new SerialPort();
sp.BaudRate = 9600;
sp.PortName = AutodetectArduinoPort();
sp.Open();
string s = "";
while (true)
{
s = sp.ReadLine();
Console.WriteLine(s);
return s;
}
}
Here's the AutodetectArduinoPort method:
public string AutodetectArduinoPort()
{
ManagementScope connectionScope = new ManagementScope();
SelectQuery serialQuery = new SelectQuery("SELECT * FROM Win32_SerialPort");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(connectionScope, serialQuery);
try
{
foreach (ManagementObject item in searcher.Get())
{
string desc = item["Description"].ToString();
string deviceId = item["DeviceID"].ToString();
if (desc.Contains("Arduino"))
{
return deviceId;
}
}
}
catch (ManagementException e)
{
/* Do Nothing */
}
return null;
}
Any solution??
This happens quite a lot with Arduino, personally I think there's a problem with the FTDI driver....certainly wouldn't be the first issue with them. What I do when this happens is physically unplug the device from the USB port, wait for the notification sound from Windows and then plug it back in again. This seems to "reset" the port and force whatever is holding it open to release it, and you're good to go again. You may need to do this quite a bit over time, so the only other tip I have is to use a cheap USB hub so that you wind up wearing out the port pins on that rather than your expensive laptop/desktop.
The error you're getting means that the port is already open. Make sure that you only call ConfigPort() once, and after you're done processing data from the Arduino, close the port with sp.Close(). I would suggest converting sp into a global variable, and subscribing to the OnClosing event of your WPF window, so you can close the port when the user closes the application.
There is a Win app tool(C#) running at terminal server which is used to download mails, process the attachment in it and update its UI. Downloading and processing of mail attachments is done using the Background Worker process which also responsible for updating the UI with mails and attachments total and processed count at that instance. There is a timer which ticks to re-initializes the same background worker process after specified duration and look for new mails.
All works fine till the time I am logged in RDC, but when I lock the system (Window key+L) or switch users and comeback to regain the same session the tool is stuck/non responsive, it happens even if I lock and unlock the system instantaneously. I used another process monitoring tool which initially showed child threads getting created and exited periodically but after it is stuck no activity is shown.
I have no clue why is it happening, is window messing is stopped or UI Controls handle are lost or or or....
Following are the chunks of code I am using:
private void tmrScheduler_Tick(object sender, EventArgs e)
{
Application.DoEvents();
if (bgwMailParser == null || (!bgwMailParser.IsBusy && !objfeMailImportNParse.Is_Parsing))
{
bgwMailParser = new BackgroundWorker();
bgwMailParser.DoWork += new DoWorkEventHandler(objfeMailImportNParse.opLoadCommonData);
bgwMailParser.DoWork += new DoWorkEventHandler(objfeMailImportNParse.StartMailImport);
if (HireCraft.Properties.Settings.Default.Close_App_After_Parsing)
bgwMailParser.RunWorkerCompleted += new RunWorkerCompletedEventHandler(opCloseApplication);
bgwMailParser.RunWorkerCompleted += new RunWorkerCompletedEventHandler(opDisposeWorker);
bgwMailParser.RunWorkerAsync();
}
Application.DoEvents();
}
below method handles the events raised by bgWorker process
private delegate void Del_updateParsedCounter(Int64 del_MailCount, Int64 del_AttchCount);
private void UpdateParsedCounter(Int64 MailCount, Int64 AttchCount)
{
try
{
if (lblMailParsedCount.InvokeRequired)
{
Del_updateParsedCounter objUpdateParsedCounter = new Del_updateParsedCounter(UpdateParsedCounter);
this.Invoke(objUpdateParsedCounter, new object[] { MailCount, AttchCount });
}
else
{
lblMailParsedCount.Text = MailCount.ToString();
lblAttchSavedCount.Text = AttchCount.ToString();
}
}
catch (Exception ex)
{
Debug.Assert(false, ex.Message, ex.StackTrace);
}
}
I identified solution to issue but forgot that I raised a question here which wasn't answered.
Well issue was the background worker thread declaring a UIControl deep down somewhere in the code.
When a thread creates a UIControl it also registers itself with SystemEvents.UserPreferenceChanged event which notifies color, theme, screen size changes, system lock/unlock etc. and to respond to which parent thread requires a message pump lacking in background worker thread, the event invoke waits for a (never coming) response causing the application to hang or act non-responsive.
http://support.microsoft.com/kb/943139 link to Microsoft support explains the same.
Hi I use WPF with Caliburn Micro and in view model class I need test connection to SQL database.
Here is method which I use for testing connection.
public bool CheckSqlServer(string sqlHost, int sqlPort)
{
try
{
IPHostEntry ipHost = Dns.Resolve(sqlHost);
IPAddress ipAddr = ipHost.AddressList[0];
var tcpCli = new TcpClient();
tcpCli.Connect(ipAddr, sqlPort);
tcpCli.Close();
return true;
}
catch
{
return false;
}
}
And I call this method in another thread
//IP is worng
if (Task<bool>.Factory.StartNew(()=>CheckSqlServer("10.10.10.20",1521)).Result)
{
Insert();
}
Problem is that UI of WPF still freeze I dont know why because I call this method in new thread not in UI thread.
In your if you call Result straight away. That makes the calling thread wait on the task in a blocking way.
You should work e.g. with ContinueWith on the Task. That will be called once the execution of the first task finished. Careful with SynchronizationContext, though!
Also, you shouldn't call TaskFactory etc. in another thread. The whole point of Task is to abstract parallelism away from using the 'low-level' threads.
Try to set the proxy to null, so that the default auto-discovery will be disabled.
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.proxy.aspx
As part of my App's startup procedure, it checks data integrity, and if it finds a problem it pops up a message to the user telling them that it might take a while to repair things.
I'm showing the message using MessageBox.Show. Because the data check is done from a worker thread, I'm switching over to the UI thread to make that call, and then setting a ManualResetEvent to tell the worker thread when the user has acknowledged the message.
I kick off the data check/load very early in the app's lifecycle from the constructor in the main Application class, by spinning off a worker thread (using the ThreadPool).
When I run with the debugger, and the message is displayed, the app just waits for input. When I run without the debugger, the app terminates after displaying the dialog for 10 seconds.
That 10 seconds is a big clue - it tells me that the OS thinks the app took too long to initialize (the OS kills apps that take too long to start up).
I think that my MessageBox.Show is blocking the UI thread before the App.RootFrameNavigating has a chance to be invoked.
My questions:
Does my diagnosis sound right?
I'd prefer to kick off my data load early, because it is almost entirely IO, except for this Message Box, and the sooner I can get my Model loaded, the better, but do you normally delay your data load until later in the app lifecycle?
Any other ideas/suggestions? I can't guarantee which page will be the start page, because the app could be resuming to any page. I'm also thinking of having the MessageBox.Show delay itself until the app has initialized, perhaps polling away for a flag set by App.RootFrameNavigating - does that make sense?
I think your problem is a result of kicking off the worker thread in the Application constructor. You should use the appropriate life-cycle event, in this case: PhoneApplicationService.Activated Event
So, the solution I've come up with is to still kick off the data load in a worker-thread from the Application's constructor, but in my PhoneService's class ShowDialog method that I invoke to invoke MessageBox.Show, I check to see if the initial navigation has occurred:
private readonly ManualResetEvent _appInitialized = new ManualResetEvent(false);
public void AppInitialized()
{
_appInitialized.Set();
}
public void ShowDialog(string caption, string text, Action<MessageBoxResult> callback, MessageBoxButton button = MessageBoxButton.OKCancel)
{
_appInitialized.WaitOne();
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
var result = MessageBox.Show(text, caption, button);
if (callback != null)
{
callback(result);
}
});
}
Then in my Application class:
private bool _firstNavigate = true;
private void RootFrameNavigating(object sender, NavigatingCancelEventArgs e)
{
if (_firstNavigate)
{
_firstNavigate = false;
var navigationService = (NavigationService) sender;
navigationService.Navigated += NavigationServiceNavigated;
}
....
private void NavigationServiceNavigated(object sender, NavigationEventArgs e)
{
var navigationService = (NavigationService)sender;
navigationService.Navigated -= NavigationServiceNavigated;
PhoneServices.Current.AppInitialized();
}
Anyone see any issues with this approach? Anyone come up with a better way?
I have an IPC problem. I have created into a windows service a NamedPipeServer:
serverPipe = new NamedPipeServerStream(Constants.PIPE_NAME, PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
Thread thread = new Thread(new ThreadStart(pipeWork));
thread.Start();
where pipeWork is
private static void pipeWork()
{
try
{
byte[] buffer = new byte[1024];
while (true)
{
if (!serverPipe.IsConnected)
serverPipe.WaitForConnection();
int nr = serverPipe.Read(buffer, 0, buffer.Length);
String str=Encoding.Default.GetString(buffer);
…
}
}
catch (Exception ex)
{
}
}
and into a Windows forms I have the client
clientPipe = new NamedPipeClientStream(".", PhotoServiceClassLibrary.Constants.PIPE_NAME, PipeDirection.InOut,PipeOptions.Asynchronous);
clientPipe.Connect();
clientPipe.ReadMode = PipeTransmissionMode.Message;
pipeThread=new Thread(new ThreadStart(pipeWork));
pipeThread.Start();
where pipeWork is
private void pipeWork()
{
try
{
while (true)
{
using (StreamReader sr = new StreamReader(clientPipe))
{
string message;
while ((message = sr.ReadLine()) != null)
{
…
}
}
}
}
catch (Exception ex)
{
}
}
I want when the service begin an action to disable a ContextMenuStrip from the windows forms, for that the service writes a message into a StreamWriter sw:
StreamWriter write = null;
write = new StreamWriter(serverPipe);
if (serverPipe.IsConnected)
{
write.Write(message);
write.Flush();
}
The code is correct because I created for testing another windows forms which implements the same things like the windows service and the communication between
windows forms pipe server -> windows forms pipe client is working well.
The problem is that the windows form - client pipe doesn't receive the message from windows service - server pipe.
I know that WCF can be a better idea but i want to understand why is not working at low-level IPC. Why? I've seen an very strange behavior. My service interact 2 times with the windows forms:
1.My service is designed for downloading some photos. When he begin download he sends a message to the windows forms to announcing him that.
2.When i stop the service he sends a message to windows forms and he stops also.
i've just discovered that both messages arrive at windows agent only after the service is stoped. Can someone explain why?
I hope this isn't your real code. It's good that you've got try/catch blocks around the code of your ThreadStart handlers (otherwise an exception would just quietly delete the thread). However, if you're not logging the exception in the catch block, then it's really just as bad.
You've got a mystery (server doesn't receive message), and you're hiding information (an exception has occurred). If you weren't hiding information, you might have the answer for your mystery (server doesn't receive message because an exception has occurred).
I'm trying to implement the same thing.
I noticed you're passing the PipeTransmissionMode.Message enumeration in the NamedPipeServerStream (serverPipe) constructor. That means the stream will contain strings.
But in pipeWork, you're reading them in as an array of bytes.
Look in the example in this article on MSDN:
http://msdn.microsoft.com/en-us/library/system.io.pipes.namedpipeclientstream.aspx