source: PinConnection/UCommThread.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.7 KB
Line 
1unit UCommThread;
2
3{$mode Delphi}{$H+}
4
5interface
6
7uses
8 Classes, SysUtils, blcksock, UCommPin, SyncObjs, UCommon,
9 DateUtils, UThreading, SpecializedList, UBinarySerializer;
10
11type
12 TCommThread = class;
13
14 TReceiveDataEvent = procedure(Stream: TMemoryStream) of object;
15
16 { TCommThreadReceiveThread }
17
18 TCommThreadReceiveThread = class(TTermThread)
19 public
20 Parent: TCommThread;
21 Stream: TBinarySerializer;
22 procedure Execute; override;
23 constructor Create(CreateSuspended: Boolean;
24 const StackSize: SizeUInt = DefaultStackSize);
25 destructor Destroy; override;
26 end;
27
28 { TCommThread }
29
30 TCommThread = class(TCommNode)
31 private
32 //FOnReceiveData: TReceiveDataEvent;
33 FReceiveThread: TCommThreadReceiveThread;
34 FInputBuffer: TBinarySerializer;
35 FInputBufferLock: TCriticalSection;
36 FDataAvailable: TEvent;
37 FStatusEvent: TEvent;
38 FStatusValue: Integer;
39 procedure PinReceiveData(Sender: TCommPin; Stream: TListByte);
40 procedure PinSetStatus(Sender: TCommPin; Status: Integer);
41 procedure ExtReceiveData(Sender: TCommPin; Stream: TListByte);
42 procedure ExtSetStatus(Sender: TCommPin; AStatus: Integer);
43 protected
44 procedure SetActive(const AValue: Boolean); override;
45 public
46 Ext: TCommPin;
47 Pin: TCommPin;
48 constructor Create(AOwner: TComponent); override;
49 destructor Destroy; override;
50 end;
51
52implementation
53
54{ TCommThread }
55
56procedure TCommThread.PinReceiveData(Sender: TCommPin; Stream: TListByte);
57begin
58 if FActive then Ext.Send(Stream);
59end;
60
61procedure TCommThread.PinSetStatus(Sender: TCommPin; Status: Integer);
62begin
63 if FActive then Ext.Status := Status;
64end;
65
66procedure TCommThread.ExtReceiveData(Sender: TCommPin; Stream: TListByte);
67begin
68 try
69 FInputBufferLock.Acquire;
70 FInputBuffer.WriteList(Stream, 0, Stream.Count);
71 FDataAvailable.SetEvent;
72 finally
73 FInputBufferLock.Release;
74 end;
75end;
76
77procedure TCommThread.ExtSetStatus(Sender: TCommPin; AStatus: Integer);
78begin
79 try
80 FInputBufferLock.Acquire;
81 FStatusValue := AStatus;
82 FStatusEvent.SetEvent;
83 finally
84 FInputBufferLock.Release;
85 end;
86end;
87
88procedure TCommThread.SetActive(const AValue: Boolean);
89begin
90 if FActive = AValue then Exit;
91 FActive := AValue;
92
93 if AValue then begin
94 FReceiveThread := TCommThreadReceiveThread.Create(True);
95 FReceiveThread.FreeOnTerminate := False;
96 FReceiveThread.Parent := Self;
97 FReceiveThread.Name := 'CommThread';
98 FReceiveThread.Start;
99 end else begin
100 FreeAndNil(FReceiveThread);
101 end;
102 inherited;
103end;
104
105constructor TCommThread.Create(AOwner: TComponent);
106begin
107 inherited;
108 FInputBuffer := TBinarySerializer.Create;
109 FInputBuffer.List := TListByte.Create;
110 FInputBuffer.OwnsList := True;
111 FInputBufferLock := TCriticalSection.Create;
112 Ext := TCommPin.Create;
113 Ext.OnReceive := ExtReceiveData;
114 Ext.OnSetSatus := ExtSetStatus;
115 Ext.Node := Self;
116 Pin := TCommPin.Create;
117 Pin.OnReceive := PinReceiveData;
118 Pin.OnSetSatus := PinSetStatus;
119 Pin.Node := Self;
120 FDataAvailable := TSimpleEvent.Create;
121 FStatusEvent := TSimpleEvent.Create;
122end;
123
124destructor TCommThread.Destroy;
125begin
126 Active := False;
127 FInputBufferLock.Acquire;
128 FreeAndNil(FInputBuffer);
129 FreeAndNil(FInputBufferLock);
130 FreeAndNil(Ext);
131 FreeAndNil(Pin);
132 FreeAndNil(FStatusEvent);
133 FreeAndNil(FDataAvailable);
134 inherited;
135end;
136
137{ TCommThreadReceiveThread }
138
139procedure TCommThreadReceiveThread.Execute;
140var
141 TempStatus: Integer;
142 DoSleep: Boolean;
143begin
144 with Parent do
145 repeat
146 DoSleep := True;
147 // Check if new data arrived
148 if FDataAvailable.WaitFor(0) = wrSignaled then begin
149 DoSleep := False;
150 try
151 FInputBufferLock.Acquire;
152 Stream.List.Assign(FInputBuffer.List);
153 FDataAvailable.ResetEvent;
154 FInputBuffer.Clear;
155 finally
156 FInputBufferLock.Release;
157 end; // else Yield;
158 Pin.Send(Stream.List);
159 end;
160
161 // Check if state changed
162 if FStatusEvent.WaitFor(0) = wrSignaled then begin
163 DoSleep := False;
164 try
165 FInputBufferLock.Acquire;
166 TempStatus := FStatusValue;
167 finally
168 FStatusEvent.ResetEvent;
169 FInputBufferLock.Release;
170 end;
171 Pin.Status := TempStatus;
172 end;
173 if not Terminated and DoSleep then begin
174 Sleep(1);
175 end;
176 until Terminated;
177end;
178
179constructor TCommThreadReceiveThread.Create(CreateSuspended: Boolean;
180 const StackSize: SizeUInt);
181begin
182 inherited;
183 Stream := TBinarySerializer.Create;
184 Stream.List := TListByte.Create;
185 Stream.OwnsList := True;
186end;
187
188destructor TCommThreadReceiveThread.Destroy;
189begin
190 Stream.Free;
191 inherited;
192end;
193
194end.
195
Note: See TracBrowser for help on using the repository browser.