source: PinConnection/UCommDelay.pas

Last change on this file was 440, checked in by chronos, 12 years ago
  • Fixed: Thread safe access to serial port pin interface using lock.
File size: 4.5 KB
Line 
1unit UCommDelay;
2
3{$mode Delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, UCommPin, UThreading, SyncObjs, SpecializedList;
9
10type
11 TCommDelay = class;
12
13 { TDelayedPacket }
14
15 TDelayedPacket = class
16 ReceiveTime: TDateTime;
17 Data: TListByte;
18 constructor Create;
19 destructor Destroy; override;
20 end;
21
22 { TCommDelayThread }
23
24 TCommDelayThread = class(TTermThread)
25 Parent: TCommDelay;
26 PacketQueue: TListObject;
27 Pin: TCommPin;
28 Lock: TCriticalSection;
29 procedure Execute; override;
30 end;
31
32 { TCommDelay }
33
34 TCommDelay = class(TCommNode)
35 private
36 FDelay: TDateTime;
37 PacketQueue1: TListObject; // TListObject<TDelayedPacket>
38 PacketQueue2: TListObject; // TListObject<TDelayedPacket>
39 Thread1: TCommDelayThread;
40 Thread2: TCommDelayThread;
41 procedure ReceiveData1(Sender: TCommPin; AStream: TListByte);
42 procedure ReceiveData2(Sender: TCommPin; AStream: TListByte);
43 protected
44 procedure SetActive(const AValue: Boolean); override;
45 public
46 Lock1: TCriticalSection;
47 Lock2: TCriticalSection;
48 Pin1: TCommPin;
49 Pin2: TCommPin;
50 constructor Create(AOwner: TComponent); override;
51 destructor Destroy; override;
52 property Delay: TDateTime read FDelay write FDelay;
53 end;
54
55implementation
56
57{ TCommDelayThread }
58
59procedure TCommDelayThread.Execute;
60var
61 I: Integer;
62 CurrentTime: TDateTime;
63 SendData: TListByte;
64 DoSleep: Boolean;
65begin
66 try
67 SendData := TListByte.Create;
68 repeat
69 DoSleep := True;
70 try
71 Lock.Acquire;
72 CurrentTime := Now;
73 I := 0;
74 while (I < PacketQueue.Count) do
75 if TDelayedPacket(PacketQueue[I]).ReceiveTime < (CurrentTime - Parent.Delay) then begin
76 DoSleep := False;
77 SendData.Assign(TDelayedPacket(PacketQueue[I]).Data);
78 PacketQueue.Delete(I);
79 try
80 Lock.Release;
81 Pin.Send(SendData);
82 finally
83 Lock.Acquire;
84 end;
85 end else Inc(I);
86 finally
87 Lock.Release;
88 end;
89 if not Terminated and DoSleep then Sleep(1);
90 until Terminated;
91 finally
92 SendData.Free;
93 end;
94end;
95
96{ TDelayedPacket }
97
98constructor TDelayedPacket.Create;
99begin
100 Data := TListByte.Create;
101end;
102
103destructor TDelayedPacket.Destroy;
104begin
105 Data.Free;
106 inherited Destroy;
107end;
108
109{ TCommDelay }
110
111procedure TCommDelay.ReceiveData1(Sender: TCommPin; AStream: TListByte);
112begin
113 try
114 Lock2.Acquire;
115 if Delay = 0 then Pin2.Send(AStream)
116 else
117 with TDelayedPacket(PacketQueue2.AddNew(TDelayedPacket.Create)) do begin
118 ReceiveTime := Now;
119 Data.Assign(AStream);
120 end;
121 finally
122 Lock2.Release;
123 end;
124end;
125
126procedure TCommDelay.ReceiveData2(Sender: TCommPin; AStream: TListByte);
127begin
128 try
129 Lock1.Acquire;
130 if Delay = 0 then Pin1.Send(AStream)
131 else
132 with TDelayedPacket(PacketQueue1.AddNew(TDelayedPacket.Create)) do begin
133 ReceiveTime := Now;
134 Data.Assign(AStream);
135 end;
136 finally
137 Lock1.Release;
138 end;
139end;
140
141procedure TCommDelay.SetActive(const AValue: Boolean);
142begin
143 if FActive = AValue then Exit;
144 FActive := AValue;
145 if AValue then begin
146 Thread1 := TCommDelayThread.Create(True);
147 Thread1.FreeOnTerminate := False;
148 Thread1.Parent := Self;
149 Thread1.Name := 'CommDelay1';
150 Thread1.PacketQueue := PacketQueue1;
151 Thread1.Pin := Pin1;
152 Thread1.Lock := Lock1;
153 Thread1.Start;
154
155 Thread2 := TCommDelayThread.Create(True);
156 Thread2.FreeOnTerminate := False;
157 Thread2.Parent := Self;
158 Thread2.Name := 'CommDelay2';
159 Thread2.PacketQueue := PacketQueue2;
160 Thread2.Pin := Pin2;
161 Thread2.Lock := Lock2;
162 Thread2.Start;
163 end else begin
164 FreeAndNil(Thread1);
165 FreeAndNil(Thread2);
166 end;
167 inherited;
168end;
169
170constructor TCommDelay.Create(AOwner: TComponent);
171begin
172 inherited;
173 Lock1 := TCriticalSection.Create;
174 Lock2 := TCriticalSection.Create;
175 PacketQueue1 := TListObject.Create;
176 PacketQueue2 := TListObject.Create;
177 Pin1 := TCommPin.Create;
178 Pin1.OnReceive := ReceiveData1;
179 Pin1.Node := Self;
180 Pin2 := TCommPin.Create;
181 Pin2.OnReceive := ReceiveData2;
182 Pin2.Node := Self;
183end;
184
185destructor TCommDelay.Destroy;
186begin
187 Active := False;
188 Pin2.Free;
189 Pin1.Free;
190 PacketQueue1.Free;
191 PacketQueue2.Free;
192 Lock1.Free;
193 Lock2.Free;
194 inherited Destroy;
195end;
196
197end.
198
Note: See TracBrowser for help on using the repository browser.