用CPort线程化

时间:2015-03-26 04:25:00

标签: multithreading delphi port pascal

我正在尝试在delphi中编写一个简单的CPort应用程序。

我希望它听一个端口,收到一条消息后,它将等待4秒然后发送一个字符串作为回应。

unit Tests.Mocks.Refractometer;

interface

uses
  CPort,
  Classes
  ;

type
  TRefractometerMock = class
    strict private
      MockRunThread : TThread;
      ComPort : TComPort;
      ComDataPacket: TComDataPacket;
    public
      procedure Open;
      procedure HandlePacket(Sender : TObject; const Str : String);

      constructor Create; overload;
      constructor Create(BaudRate : TBaudRate; Port : String); overload;
      destructor Destroy; override;
  end;

implementation

uses
  SysUtils,
  StrUtils
  ;

procedure TRefractometerMock.HandlePacket(Sender : TObject; const Str : String);
begin
    MockRunThread.Start;    
end;

procedure TRefractometerMock.Open;
begin
    ComPort.Open;
end;

constructor TRefractometerMock.Create(BaudRate : TBaudRate; Port : String);
begin
    Self.Create;
    Self.ComPort.Port := Port;
    Self.ComPort.BaudRate := BaudRate;
end;

constructor TRefractometerMock.Create;
begin
    inherited;
    ComPort := TComPort.Create(nil);
    ComDataPacket := TComDataPacket.Create(nil);

    ComDataPacket.ComPort := ComPort;
    ComDataPacket.OnPacket := HandlePacket;

    MockRunThread := TThread.CreateAnonymousThread
    (
        procedure
        begin
            Sleep(4000);
            Self.ComPort.WriteStr('nD=1.33308;');
        end
    );
end;

destructor TRefractometerMock.Destroy;
begin
    if Assigned(Self.ComPort)  then FreeAndNil(Self.ComPort);
    if Assigned(ComDataPacket) then FreeAndNil(ComDataPacket);
    if Assigned(MockRunThread) then FreeAndNil(MockRunThread);

    inherited;
end;

end.

使用此单元我可以使用以下代码

开始聆听

RefractometerMock := TRefractometerMock.Create(TBaudRate.br9600, 'COM7');
try
    RefractometerMock.Open;

    Sleep(8000);

finally
    FreeAndNil(RefractometerMock);
end;

另请注意,我正在使用com0com在端口COM6COM7之间创建桥接。

我在端口COM6

上发送了一条putty消息

putty

问题在于即使我发送了一条带putty的消息,在释放HandlePacket对象之前也不会调用TRefractometerMock方法。

首先 Start

然后

handle

然后

anon

最后

error

thread handle

我甚至不确定这是怎么可能的,因为我认为这个物体已经被毁坏了。

3 个答案:

答案 0 :(得分:3)

您正在Sleep(8000)阻止主线程。这意味着com端口驱动程序无法调用HandlePacket方法。

当睡眠结束时,处理任何事都为时已晚,因为一切都已被释放。

由于您正在处理匿名线程的生命周期,因此应将FreeOnTerminate属性设置为false。并在匿名线程之后释放com端口。

使用计时器代替Sleep()来电。

答案 1 :(得分:0)

我没有看到ComDataPacket的任何设置。来自帮助:Packet ends when one of stop conditions occurs。你有没有定义这些停止条件?
您是否在简单的独立应用程序中使用ComDataPacket检查了数据接收,没有中间类?

BTW,似乎TTimer可以完成这项工作,这里不需要线程。

答案 2 :(得分:0)

由于布莱恩弗罗斯特想要这里的代码,这太大了,不适合评论。

创建一个简单的表单

type
  TFrmMockRefrac = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    RefractometerMock : TRefractometerMock;
    { Public declarations }
  end;

var
  FrmMockRefrac: TFrmMockRefrac;

在没有Sleep功能的情况下处理创建和销毁

procedure TFrmMockRefrac.FormCreate(Sender: TObject);
begin
    RefractometerMock := TRefractometerMock.Create(TBaudRate.br9600, 'COM7');
    RefractometerMock.Open;
end;

procedure TFrmMockRefrac.FormDestroy(Sender: TObject);
begin
    FreeAndNil(RefractometerMock);
end;