Delphi Prism中的TimeOutException和SerialPort

Delphi Prism中的TimeOutException和SerialPort,exception,exception-handling,timeout,serial-port,delphi-prism,Exception,Exception Handling,Timeout,Serial Port,Delphi Prism,我需要我的程序在每次SerialPort读取超时时捕获TimeOutException,但它无法做到这一点。实际上,程序在读取时会中断并抛出此异常,“由于线程退出或应用程序请求,I/O操作已中止。” 以下是SerialPort的实例化方式: dxComm = class(System.Windows.Forms.Form) private protected public constructor; serialPort1:System.IO.Ports.SerialPort;

我需要我的程序在每次SerialPort读取超时时捕获TimeOutException,但它无法做到这一点。实际上,程序在读取时会中断并抛出此异常,“由于线程退出或应用程序请求,I/O操作已中止。”

以下是SerialPort的实例化方式:

dxComm = class(System.Windows.Forms.Form)
private
protected
public
    constructor;
    serialPort1:System.IO.Ports.SerialPort;
    thr:Thread;
    method mythread;
end;

constructor DXComm;
begin
  //
  // Required for Windows Form Designer support
  //
  InitializeComponent();

  //
  // TODO: Add any constructor code after InitializeComponent call
  //
  SerialPort1 := new System.Io.Ports.SerialPort();
  thr:=nil;
end;
以下是创建线程的方式:

          thr:= new Thread(@mythread);
          thr.Start;
以下是串行端口设置:

   case TypeDXCard.SelectedIndex of

    0:
      begin
        DXProtocol := TDXProtocol.tDxTwo;
        msglen := 6;
        rmsglen := 5;
      end;
    1:
      begin
        DXProtocol := TDXProtocol.tDxExpress;
        msglen:=0;
        rmsglen:=0;
      end;

    else
      begin
        DXProtocol := TDXProtocol.tDxTwo;
        msglen := 6;
        rmsglen := 5;
      end;
  end;

  dx := ord(DXProtocol);

  if (SerialPort1 <> nil) then
  begin
      case CommPort.SelectedIndex of
        0: SerialPort1.PortName := 'COM1';
        1: SerialPort1.PortName := 'COM2';
        2: SerialPort1.portName := 'COM3';
        3: SerialPort1.PortName := 'COM4';
      end;    

       case BaudRate.SelectedIndex of
         0: SerialPort1.BaudRate := 1200;
         1: SerialPort1.BaudRate := 2400;
         2: SerialPort1.BaudRate := 4800;
         3: SerialPort1.BaudRate := 9600;
         4: SerialPort1.BaudRate := 19200;
         5: SerialPort1.BaudRate := 38400;
         6: SerialPort1.BaudRate := 57600;
         7: SerialPort1.BaudRate := 115200;
      end;

      if (EvenParity.Checked) then
        SerialPort1.Parity := System.IO.Ports.Parity.Even
      else
        SerialPort1.Parity := System.IO.Ports.Parity.None;
  end;

  with SerialPort1 do
  begin
    SerialPort1.DataBits:=8;
    SerialPort1.DtrEnable:=true;
    SerialPort1.ReadBufferSize:= 4096;
    SerialPort1.ReadTimeout:=TimeOutDelay*2;
    SerialPort1.RtsEnable:=true;
    SerialPort1.StopBits:=System.IO.Ports.StopBits.One;
    SerialPort1.WriteTimeout:=1000;
    SerialPort1.Handshake := HandShake.None;
    SerialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(@MySerialData);
  end;
case TypeDXCard.SelectedIndex of
0:
开始
DXProtocol:=TDXProtocol.tDxTwo;
msglen:=6;
rmsglen:=5;
结束;
1:
开始
DXProtocol:=TDXProtocol.tDxExpress;
msglen:=0;
rmsglen:=0;
结束;
其他的
开始
DXProtocol:=TDXProtocol.tDxTwo;
msglen:=6;
rmsglen:=5;
结束;
结束;
dx:=ord(dx协议);
如果(串行端口1为零),则
开始
case CommPort.SelectedIndex of
0:SerialPort1.PortName:=“COM1”;
1:SerialPort1.PortName:=“COM2”;
2:SerialPort1.portName:=“COM3”;
3:SerialPort1.PortName:=“COM4”;
结束;
案例波特率。选择的索引
0:SerialPort1.BaudRate:=1200;
1:SerialPort1.BaudRate:=2400;
2:SerialPort1.BaudRate:=4800;
3:SerialPort1.BaudRate:=9600;
4:SerialPort1.BaudRate:=19200;
5:SerialPort1.BaudRate:=38400;
6:SerialPort1.BaudRate:=57600;
7:SerialPort1.BaudRate:=115200;
结束;
如果(EvenParity.Checked)那么
SerialPort1.Parity:=System.IO.Ports.Parity.偶数
其他的
SerialPort1.Parity:=System.IO.Ports.Parity.None;
结束;
用SerialPort1做什么
开始
SerialPort1.数据位:=8;
SerialPort1.DtrEnable:=true;
SerialPort1.ReadBufferSize:=4096;
SerialPort1.ReadTimeout:=TimeOutDelay*2;
SerialPort1.RtsEnable:=true;
SerialPort1.StopBits:=System.IO.Ports.StopBits.One;
SerialPort1.WriteTimeout:=1000;
SerialPort1.Handshake:=Handshake.None;
SerialPort1.DataReceived+=新系统.IO.Ports.SerialDataReceiveDevenHandler(@MySerialData);
结束;
这是我处理SerialPort的线程。请编写:

method DXcomm.mythread;
var x,y:Integer;
begin
    while true do
    begin        
        Thread.Sleep(ScanTime);
        SerialPort1.RtsEnable:=true;
        SerialPort1.DiscardOutBuffer;
        SendMessage;   <---------Assembles the bytes and sends it out
        while SerialPort1.BytesToWrite>0 do;
        thread.Sleep(4);
        SerialPort1.DiscardInBuffer;
        SerialPort1.RtsEnable:=false;

        if (stopthread) then
            break;
    end;
end;
方法DXcomm.mythread;
变量x,y:整数;
开始
尽管如此
开始
线程。睡眠(扫描时间);
SerialPort1.RtsEnable:=true;
SerialPort1.1.1.1.1;
发送消息;0 do;
睡眠(4);
SerialPort1.DiscardInBuffer;
SerialPort1.RtsEnable:=false;
如果(停止线程)那么
打破
结束;
结束;
以下是从serialport读取字节的事件:

method DXComm.MySerialData(sender: System.Object; e:SerialDataReceivedEventArgs);
begin
    if not SerialPort1.IsOpen then Exit;   

    try
        SerialPort1.Read(RXMsg,0,5); <------Here is Where my program throws that exception when I check on TimeOutException down below.

          if changeFlag then
          begin
               changeList.IncRxCnt;
               FixUpChangeList;
          end
          else
              ActiveUnit.Retreive;       
    except on ex: TimeOutException do <----This line of code fails.
    //except on ex: Exception do      <----This line of code works fine, but executes all the time instead of just only when there is an exception.
    begin
        //TimeOut Exception
        ActiveUnit.Timeout;
        SerialPort1.DiscardInBuffer;
        SerialPort1.DiscardOutBuffer;
    end;
    end;
end;
方法DXComm.MySerialData(发送方:System.Object;e:SerialDataReceivedEventArgs);
开始
如果不是SerialPort1.IsOpen,则退出;
尝试
SerialPort1.Read(RXMsg,0,5) 而不是:
SerialPort1.Read(RXMsg,0,5)

Delphi是否有一个串行函数,用于返回接收到并等待读取的字符数

例如(在可能较差的伪代码中):


看起来您正在使用串行端口作为窗体上的组件,但在后台线程中进行读/写操作

或者,如我所知,你在后台线程中编写,然后在其他一些随机线程(调用你对其作出反应的事件的线程)上阅读

这是一个问题,因为后台线程(内部)希望更新串行端口“控制”,这是后台线程不允许的。问题还可能是等待读取的线程被另一个正在无限循环中写入的线程中断,从而导致I/O异常。这里有点猜测

第一枪: 您必须动态创建串行端口(即不将其放在窗体上,而是通过代码实例化和配置它)以防止出现这种情况,或者(强烈建议)将
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls
设置为false

第二枪:
另一方面,我强烈建议确定只有一个线程在使用串行端口。不在一条线上写,也不在另一条线上读。在一个线程中执行与此串行I/O相关的所有操作。读取或写入,但不要尝试从不同线程同时执行这两项操作。

我认为问题在于,我在自己的线程或用户定义的线程中写入serialport,而在另一个线程中从serialport读取。我认为,接收到的事件数据是程序主线程的一部分

正如Sebastian所指出的,从同一个线程进行写和读应该可以解决我的串行通信问题。事实上,它似乎已经解决了我的串行通信问题,尽管它还不到100%。这是一个时间问题,因为我的程序依赖于固定的时间延迟

步骤:在我的线程中,我写入串行端口并等待某个时间从串行端口读取响应。这似乎极大地改善了通信,但现在我不必等到datareceived事件在输入缓冲区中看到某个内容时触发


如果我的想法或推理错误,请纠正我。

这是Delphi Prism,因此是纯.Net。@Sebastian,SerialPort是在Winform类中动态创建的,而不是作为控件放置在窗体上。我相信我只有一个线程直接处理串口通信。我建议在读取行之前调试和检查线程ID、每次发送的线程ID以及发生异常的线程ID。我真想知道是否所有的线程都是一样的。@Sebastian,你是对的,线程每隔一段时间或在循环数之后切换它的ID,但是只有一个线程。这是因为方法MySerialData是dxCommWin窗口窗体的一部分吗?@Sebastian,我在调试线程时看到了更多有趣的东西。似乎不是
while (Not Timeout)
{
    if (serialport1.characterswaiting)
    {
        SerialPort1.Read(RXMsg,0,5);
    }
}