线程池,线程安全队列,OOP

时间:2015-10-30 11:21:03

标签: multithreading delphi queue threadpool indy

假设以太网上有一些非PC设备,并且基于给定的API,我可以使用UDP与它们通信。

我想使用线程池和线程安全队列进行UDP通信。每个工作线程都有自己的indy TIdUDPclient实例。通信就像将一个UDP数据报发送到设备然后等待答案。答案是UDP数据报在数据段中具有> 2个字节。

设备由 TDevice 类实例表示。

TDevice = class(TObject)
private
  ...
  FStatus: byte;
  ...
public
  ...
  function GetStatus(): integer; //API commandID = 68 (Getting device Status)
end;

thPool 用于创建/管理线程并将作业推送到队列:

TthPool = class(TObject)
private
  FQueue: TThreadedQueue<TrUDPdirectJob*>;
  FthWorkers: TList<TthWorker>;
public
  constructor Create( AthCount, AQueueDepth: integer); //creating the pool here
  function SendCommand( ArSendJob: TrSendJob );
end;

function SendCommand(ArSendJob TrSendJob): integer; 
begin
  ...
  FQueue.PushItem( ArSendJob );
end;

TDevice 的一个功能是获取它所代表的硬件的状态,并根据收到的答案设置它的 FStatus 的值:

function TDevice.GetStatus(): integer;  //command byte: 68
const
  PARAMSLENGTH = 4;
var
  rSendJob: TrSendJob*        
begin
  rSendJob.IP := self.FIP;
  rSendJob.port := self.Fport;
  rSendJob.commandID := 68;
  rSendJob.paramslength := PARAMLENGTH ; //need to send the length (API req) 
  SetLength( rSendJob.params, PARAMSLENGTH  );  
  rSendJob.params[0] := $A; //just some parameters along the commandID
  rSendJob.params[1] := $B;
  rSendJob.params[2] := $C;
  rSendJob.params[3] := $D;
  ...
  thPool.SendCommand( rSendJob );   //pushing the job to the queue   
end;

*TrSendJob = record  //Job define
  ip: string;
  port: integer;
  commandID: byte;        
  params: Tparams; //Array of byte
  paramslength: byte;
end;

从工作线程发送UDP数据报:

procedure TthWorker.Execute;
var
  sendBuffer: TIDbytes;
  rBuffer: TIdBytes;
  rSendJob: TrSendJob;
begin
  inherited;
  repeat
    FQueue.PopItem(rSendJob); //Getting the job from the queue
    //Building the sending buffer
    sendBuffer[0] := rSendJob. ... ; 
    ...
    FIdUDPclient.SendBuffer( rSendJob.IP, rSendJob.port, sendBuffer );
    if FIdUDPclient.receiveBuffer(rbuffer, RECTIMEOUT_GLOBAL) >= 1 then
    begin
      //
    end;
  until Terminated;
end;

总之, thPool SendCommand 正在将作业推入队列,工作线程从队列中拉出作业并发送UDP数据报,然后它回到 rbuffer 中的答案字节。但此时,如何将receivebuffer的内容发送回 TDevice 实例进行处理?这样做的正确(OOP)方式是什么?我需要在 TDevice 方法中进行处理。

这是一个合适的解决方案,如果我在 TrSendJob 定义一个加号方法指针字段,那么工作线程知道调用哪个方法来处理缓冲区并设置 FState 值of TDevice

TProcessReceiveBuffer = function(ArBuffer: TIdBytes): integer;

TrSendJob = record  //Job define
  ip: string;
  port: integer;
  commandID: byte;        
  params: Tparams; //Tparams array of byte
  paramslength: byte;
  *ProcessReceiveBuffer: TProcessReceiveBuffer; //pointer to a TDevice method thats processing the receivebuffer
end;

或者,整个概念都是错误的。

1 个答案:

答案 0 :(得分:2)

  

但是在这一点上,如何将receivebuffer的内容发送回TDevice实例进行处理?

您可以在TrSendJob中添加TthWorker对象指针,然后TDevice将知道将TEvent传递给缓冲区。

或者,您可以将缓冲区和TrSendJob放入TthWorker,然后让TDevice.GetStatus()填充缓冲区并发出事件信号,然后让.button span { font-family: 'Georgia'; text-transform: uppercase; font-size: 13px; color: #FFFFFF; position: absolute; top: 20px; left: 40px; z-index: 2; background: url('http://mile.x3.rs/mile/palma/img/button.gif') no-repeat; padding: 14px 37px 30px 37px; } .button:hover span:hover{background: url('http://mile.x3.rs/mile/palma/img/button_active.gif') no-repeat;} .button:hover span, .button:hover:before {color: #88bfaa;}等待事件信号并处理缓冲区。