Winforms WinForm应用程序停止运行并冻结windows

Winforms WinForm应用程序停止运行并冻结windows,winforms,Winforms,我不熟悉Windows开发。 我开发了一个WinForm应用程序,它可以与串行设备通信并在图表上绘制数据。 应用程序应每天7/7天24小时运行。代码执行正确,但在执行数小时后,UI冻结在无响应操作系统上(我必须关闭电脑并重新启动) 串行类(使用System.IO.port)在单独的线程上执行读写操作。 这个场景让我想到了从串行类到UI的一个不正确的跨线程调用。阅读微软的文档和其他问题,我想我已经修复了错误,但没有办法,应用程序继续冻结操作系统 写操作通过串行方式每100ms向主板发送一个请求字符

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

串行类(使用
System.IO.port
)在单独的线程上执行读写操作。 这个场景让我想到了从串行类到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.port
,它也在一个单独的线程上执行,接收到的数据将被详细说明,然后通过一个事件处理程序委托传递给UI,该委托在主窗体类上声明了args。我将表单控件传递给serial类以进行安全线程调用

// 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());
    }
}
也许错误不在这里,但在我看来,在窗口崩溃之前,这似乎是唯一感兴趣的部分。对不起,我的英语不好,希望我提出了一个正确/不重复的问题。

使用
Control.BeginInvoke
而不是
Control.Invoke
根据我的经验,
System.IO.Ports.SerialPort
的问题通常只会导致UI冻结,而不会导致操作系统冻结,当试图使用
控件从
SerialPort.DataReceived
事件更新UI时出现死锁。调用
,UI线程本身尝试访问
SerialPort
对象,例如关闭它。在这种情况下,当UI线程等待
SerialPort
DataReceived
线程完成,而
DataReceived
线程等待UI线程完成
控件时,可能会出现死锁。调用
。为了克服这类问题,最好使用
Control.BeginInvoke
,这样
DataReceived
线程就不会等待UI线程

使用
lock
同步对共享资源的访问 从不同线程访问同一对象时,用于同步数据访问。无同步数据访问可能会导致所有不同的问题

检查串行端口驱动程序或连接是否有问题 当UI冻结且操作系统无响应时,请尝试移除串行端口设备,并查看操作系统是否响应。如果是这样,问题可能不在应用程序中,而在串行端口驱动程序或连接中


希望这有帮助

谢谢,我更正了代码并找出了问题所在。它不是在串行通信上,也不是无效的跨线程操作,而是在另一个FTDI设备或驱动程序上。
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();
    }
}