winforms - WinForm 应用程序停止运行并卡住窗口

标签 winforms

我是 Windows 开发新手。 我开发了一个 WinForm 应用程序,它与串行设备通信并在图表上绘制数据。 该应用程序应每天 7/7 24 小时运行。代码执行正确,但执行几个小时后,UI 卡住,操作系统无响应(我必须关闭电脑并重新启动)。

Serial 类(使用 System.IO.Ports)在单独的线程上执行读取和写入操作。 这种情况让我想到从我的串行类到 UI 的不正确的跨线程调用。阅读微软文档和其他问题,我想我修复了错误,但没办法,应用程序继续卡住操作系统。

写操作通过串口每 100ms 向开发板发送一个请求字符,我使用 System.Threading.Timer 来执行此操作,因为此操作不会与 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());
        }
    }
}

串行板用 10 个字节的字符串回复请求字符,以读取我正在使用 DataReceived 事件处理程序形式 IO.Ports 的消息,即也在单独的线程上执行,接收到的数据将被详细说明,然后通过事件处理程序委托(delegate)传递给 UI,并在主表单类上声明 args。我将表单控件传递给串行类以进行安全的线程调用。

// 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 线程(Form1 类):

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();
    }
}

也许错误不在这里,但在 Windows 崩溃之前,在我看来,这是唯一感兴趣的部分。抱歉我的英语不好,希望我提出了一个正确/不重复的问题。

最佳答案

使用Control.BeginInvoke而不是Control.Invoke

根据我的经验,通常出现 System.IO.Ports.SerialPort 的问题仅导致 UI 卡住,而不是操作系统卡住,并且是由尝试从 SerialPort .DataReceived 更新 UI 时发生死锁引起的。事件使用 Control.Invoke并且 UI 线程本身尝试访问 SerialPort例如关闭它的对象。在这种情况下,当 UI 线程等待 SerialPort 时,可能会出现死锁。 DataReceived线程完成和 DataReceived线程正在等待 UI 线程完成 Control.Invoke 。要克服此类问题,最好使用 Control.BeginInvoke所以DataReceived线程不等待 UI 线程。

使用lock同步对共享资源的访问

当从不同线程访问同一个对象时,使用 lock 同步数据访问。没有同步的数据访问会导致所有不同的奇怪问题。

检查是否是串口驱动或连接问题

当 UI 卡住并且操作系统变得无响应时,请尝试删除串行端口设备并查看操作系统是否变得响应。如果是这样,问题可能不在于应用程序,而在于串口驱动程序或连接。

希望这有帮助

关于winforms - WinForm 应用程序停止运行并卡住窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59036291/

相关文章:

c# - 在设计时向我的 'on-the-fly' 用户控件添加控件..?

winforms - 如何从事件处理函数中退出 Windows 窗体应用程序?

c# - 无法将图像转换为 bytes[] C#

c# - 获取 Windows 窗体的大小

c# - NumericUpDown 控件可以做到这一点吗?

c# - 请帮助我使这段代码线程安全

c# - 悬停并单击时更改标签的颜色

c# - 使用未分配的局部变量错误将 int var 转换为 string var

winforms - 如何在c# windows应用程序中上传多个文件

c# - 如何正确获取 WinForms Button 控件来绘制自定义文本