Autor Beitrag
daywalker0086
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 243


Delphi 2005 Architect
BeitragVerfasst: Mo 11.01.16 11:30 
Hallo Leute, ein frohes Neues wünsch ich noch.
leider habe ich auch ein Problem und sehe den Fehler nicht.
Es geht darum das Zwei Threats auf eine Variable zugreifen und diese vreändern sollen.
Ich hätte gedacht die Veränderun gin eine Critical Section zu packen, aber leider hängt sich mein Programm auf, obwohl ein Recourcenschutzblock darum ist.
Wie könnte man es besser machen?
Wenn ich die criticalsection.enter und leave auskommentiere und das programm laufen lasse, hängt sich da nichts auf, obwohl beide Threats ca. alle 15ms auf die Funktion zugreifen. Aber ich habe die Befürchtung dass dies irgendwann im Programm mal passieren könnte.
Aber hier der Code:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
unit Bootloader;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, xmldom, XMLIntf, msxmldom, XMLDoc, dkAdomCore,
  IdBaseComponent, IdCoder, IdCoder3to4, IdCoderMIME, Pcanbasic, ExtCtrls, syncobjs ;

type
  TCAN_RECEIVE = class(TThread)
  protected
  procedure Execute; override;
  end;

type
  TForm1 = class(TForm)
    pack: TButton;
  unpack: TButton;
    Button1: TButton;
  DomImplementation1: TDomImplementation;
    XmlToDomParser1: TXmlToDomParser;
  XMLDoc: TXMLDocument;
  device_list: TListBox;
  Dateiinhalt: TLabel;
  Button2: TButton;
    Button3: TButton;
  Edit1: TEdit;
  Button4: TButton;
  Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
  procedure Button4Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  procedure Button3Click(Sender: TObject);
  procedure FormClose(Sender: TObject; var Action: TCloseAction);
  procedure Button2Click(Sender: TObject);
  procedure unpackClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  procedure packClick(Sender: TObject);



  private
  { Private-Deklarationen }
  //CAN Variablen
  stsResult : TPCANStatus;
  m_PcanHandle : TPCANHandle;
  CAN_RECEIVE: TCAN_RECEIVE;
  m_hEvent : THandle;
  testcount : integer;
  FBufferCritSect: TCriticalSection;
  can_status : TPCANStatus;
  public
  { Public-Deklarationen }
  procedure Processmessage(indication: boolean);
  end;

var
  Form1: TForm1;
  testvar : integer;
 const
  CT64: array[0..63of ansichar = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

implementation

{$R *.dfm}
uses
can, uTBase64;

procedure TForm1.Processmessage(indication: boolean);
begin
  FBufferCritSect.Enter;
  try
  begin
  if indication  then
  begin
    inc(testvar);
    edit1.Text := inttostr(testvar);
  end
  else
  begin
    dec(testvar);
    edit1.Text := inttostr(testvar);
  end;
  end;
  finally
  FBufferCritSect.Leave;
  end;
end;

procedure TCAN_RECEIVE.Execute;
  var
  can_status : TPCANStatus;
  strMsg: array [0..256of Char;
  msg: TPCANMsg;
begin
  try
  can_status := TPCANBasic.SetValue(Form1.m_PcanHandle, PCAN_RECEIVE_EVENT ,PLongWord(@Form1.m_hEvent), sizeof(Form1.m_hEvent));

  repeat
    // Prüfen den Empfangspuffer nach neue Nachrichten.
    //
    if (WaitForSingleObject(Form1.m_hEvent, INFINITE) = WAIT_OBJECT_0) then
    begin  //showmessage('Daten angekommen');
    can_status := TPCANBasic.Read(Form1.m_PcanHandle, msg);
    If (can_status = PCAN_ERROR_OK) Then
    begin
                // Verarbeitung der ankommenden Nachricht.
      //
      //MessageBox(0,'A message was received','Success', MB_OK);
      //ProcessMessage(msg);
      inc(form1.testcount);
       //  Form1.Edit1.Text:= (inttostr(form1.testcount));
    Form1.Processmessage(true);

    end ;
    end;
     //  else
    //begin
      // Ein Fehler ist aufgetreten. Die Rückgabewert wird in Text umgewandelt und angezeigt.
      //
       //  TPCANBasic.GetErrorText(result, 0, strMsg);
      //MessageBox(0, strMsg, 'Error',MB_OK);
      // Den Fehler wird behandelt. Hier wird entschieden ob die Schleife beendet werden muss
      // (z.B. der Hardware befindet sich im bus-off Zustand).
      //
      //HandleReadError(result);
    //end;
  // Es wird versucht Nachrichten aus dem Empfangspuffer auszulesen,
  // bis der Empfangspuffer leer ist.
  //
  until  ((LongWord(can_status) AND LongWord(PCAN_ERROR_QRCVEMPTY)) <> 0);

   //  tpcanbasic.




  except
    on e: exception do begin
    // mache hier irgendetwas mit dem Fehler.
    end;
  end;
end;


function GetFormatedError(error: TPCANStatus) : AnsiString;
var
  status : TPCANStatus;
  buffer : array[0..255of Ansichar;
begin
  // Gets the text using the GetErrorText API function
  // If the function success, the translated error is returned. If it fails,
  // a text describing the current error is returned.
  //
  status := TPCANBasic.GetErrorText(error, 0, buffer);
  if(status <> PCAN_ERROR_OK) then
    result := Format('An error ocurred. Error-code''s text (%Xh) couldn''t be retrieved', [Integer(error)])
  else
    result := buffer;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  strTemp : AnsiString;

begin
  //stsResult := tpcanbasic.Initialize(PCAN_USBBUS1 ,PCAN_BAUD_250K);
  strTemp := 'PCAN_USB 1 (51h)';


  //showmessage(strTemp);
  strTemp := Copy(strTemp, Pos('(',strTemp) + 12);
  m_PcanHandle := TPCANHandle(StrToInt('0x'+strTemp));
  stsResult := TPCANBasic.Initialize(m_PcanHandle, PCAN_BAUD_250K,PCAN_TYPE_ISA, StrToInt('0x'+'0100'), StrToInt('0x'+'3'));

  if (stsResult <> PCAN_ERROR_OK) then
  MessageBox(0, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR)
  else
  CAN_RECEIVE.Resume;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  tpcanbasic.Uninitialize(PCAN_USBBUS1);
  FBufferCritSect.Free;
end;

procedure TForm1.Button3Click(Sender: TObject);
var
CANMsg : TPCANMsg;
begin
    CANMsg.ID := 2;
    CANMsg.MSGTYPE := PCAN_MESSAGE_EXTENDED;
    CANMsg.LEN := 8;
    CANMsg.DATA[0] := StrToInt('0x' + '35');
    CANMsg.DATA[1] := StrToInt('0x' + '36');
    CANMsg.DATA[2] := StrToInt('0x' + '38');
    CANMsg.DATA[3] := StrToInt('0x' + '40');
    CANMsg.DATA[4] := StrToInt('0x' + '41');
    CANMsg.DATA[5] := StrToInt('0x' + '45');
    CANMsg.DATA[6] := StrToInt('0x' + '46');
    CANMsg.DATA[7] := StrToInt('0x' + '47');

    stsResult := tpcanbasic.Write(m_PcanHandle,CANMsg)  ;
    if (stsResult <> PCAN_ERROR_OK) then
    MessageBox(0, PChar(GetFormatedError(stsResult)), 'Error!',MB_ICONERROR)    ;
    if Timer1.Enabled then
    timer1.Enabled := false
    else
    timer1.Enabled := true;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  CAN_RECEIVE := TCAN_RECEIVE.Create(True);
  CAN_RECEIVE.FreeOnTerminate := True;
  m_hEvent := CreateEvent(nil, False, False, '');
  FBufferCritSect := TCriticalSection.Create;
end;

procedure TForm1.Button4Click(Sender: TObject);
var
  result : TPCANStatus;
  strMsg: array [0..256of Char;
  msg: TPCANMsg;
begin
  repeat
    // Prüfen den Empfangspuffer nach neue Nachrichten.
    //
    result := TPCANBasic.Read(m_PcanHandle, msg);
    If (result = PCAN_ERROR_OK) Then
    begin
            // Verarbeitung der ankommenden Nachricht.
      //
      MessageBox(0,'A message was received','Success', MB_OK);
      //ProcessMessage(msg);
      showmessage(inttostr(msg.DATA[0]));
    end
    else
    begin
      // Ein Fehler ist aufgetreten. Die Rückgabewert wird in Text umgewandelt und angezeigt.
      //
      TPCANBasic.GetErrorText(result, 0, strMsg);
      MessageBox(0, strMsg, 'Error',MB_OK);
      // Den Fehler wird behandelt. Hier wird entschieden ob die Schleife beendet werden muss
      // (z.B. der Hardware befindet sich im bus-off Zustand).
      //
      //HandleReadError(result);
    end;
  // Es wird versucht Nachrichten aus dem Empfangspuffer auszulesen,
  // bis der Empfangspuffer leer ist.
  //
  until ((TPCANStatus(Integer(result) AND Integer(PCAN_ERROR_QRCVEMPTY))) = PCAN_ERROR_QRCVEMPTY);


end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
CANMsg : TPCANMsg;
begin
  CANMsg.ID := 2;
  CANMsg.MSGTYPE := PCAN_MESSAGE_EXTENDED;
  CANMsg.LEN := 8;
  CANMsg.DATA[0] := StrToInt('0x' + '35');
  CANMsg.DATA[1] := StrToInt('0x' + '36');
  CANMsg.DATA[2] := StrToInt('0x' + '38');
  CANMsg.DATA[3] := StrToInt('0x' + '40');
  CANMsg.DATA[4] := StrToInt('0x' + '41');
  CANMsg.DATA[5] := StrToInt('0x' + '45');
  CANMsg.DATA[6] := StrToInt('0x' + '46');
  CANMsg.DATA[7] := StrToInt('0x' + '47');

  can_status := tpcanbasic.Write(m_PcanHandle,CANMsg)  ;
  if (can_status <> PCAN_ERROR_OK) then
  begin
    Timer1.Enabled := false;
    MessageBox(0, PChar(GetFormatedError(can_status)), 'Error!',MB_ICONERROR);
  end;
  If (can_status = PCAN_ERROR_OK) Then
  Processmessage(false);
end;

end.
Nersgatt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1581
Erhaltene Danke: 279


Delphi 10 Seattle Prof.
BeitragVerfasst: Mo 11.01.16 11:35 
Vielleicht hat es damit gar nichts zu tun.
Du greifst in TForm1.Processmessage auf edit1.text zu. Und da Du Prozessmessage aus dem Thread heraus aufrufst, wird das ja auch im Threadkontext aufgerufen. Zugriffe auf Steuerelemente musst aber grundsätzlich!! im Mainthread machen (sprich: Synchronize verwenden).
Wenn man sowas macht, führt das oft zu ganz seltsamen Phänomenen. Von daher kommentiere mal die Zugriffe auf die Steuerelemente aus.

_________________
Gruß, Jens
Zuerst ignorieren sie dich, dann lachen sie über dich, dann bekämpfen sie dich und dann gewinnst du. (Mahatma Gandhi)
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Mo 11.01.16 12:04 
Hallo,

Drei Sachen fallen mir auf:
  1. Die Dinger heißen Threads, sonst wird eine Drohung draus ;)
  2. CANMsg.DATA[0] := StrToInt('0x' + '35'); Das passt so nicht, StrToInt hat wie Delphi allgemein $ als Präfix für Hex-Zahlen, das wäre also entweder CANMsg.DATA[0] := StrToInt('$' + '35'); oder direkt CANMsg.DATA[0] := $35;
  3. Wie user profile iconNersgatt schon schreibt, darf der Zugriff auf Steuerelemente nur im Mainthread passieren. Ich vermute, hier liegt ein Verständnisproblem vor, weil du die CriticalSection so benutzt, als würde sie das tun. Eine CS ist aber nur so etwas wie ein Fahrsignal bei der Bahn, und stellt sicher dass nur exakt ein Thread im Bereich zwischen Enter und Leave ist, und der nächste erst dann Entern kann, nachdem der aktuelle definitiv raus ist. Du könntest damit zum Beispiel dafür sorgen, dass die Ausgabe im Mainthread und die Datenverarbeitung im CAN-Thread sich nicht in die Quere kommen.


Viele Grüße,
Martok

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
daywalker0086 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 243


Delphi 2005 Architect
BeitragVerfasst: Mo 11.01.16 12:06 
Hallo Jens, und auch danke Martok,
danke für die Antwort. Hab den Zugriff mal auskommentiert und lasse mir die Variablenänderung nun mit einem zweiten Timer auf das Edit aktualisieren.
So läuft das auf jeden Fall.
Dann mach ich mal so weiter. Vielen Dank.
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Mo 11.01.16 12:30 
Noch ein Nachtrag:
user profile icondaywalker0086 hat folgendes geschrieben Zum zitierten Posting springen:
Hab den Zugriff mal auskommentiert und lasse mir die Variablenänderung nun mit einem zweiten Timer auf das Edit aktualisieren.
Genau, da würdest du dann in der CAN-Verarbeitung sowas haben:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
FBufferCritSect.Enter;
try
  inc(form1.testcount);
finally
  FBufferCritSect.Leave;
end;


Und im Timer dann
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
FBufferCritSect.Enter;
try
  Edit1.Text:= IntToStr(testvar);
finally
  FBufferCritSect.Leave;
end;


Das stellt dann sicher, dass du nicht grade auf die Variable fasst während sie geschrieben wird und besonders wenn es dann mehrere Variablen werden wird das wichtig, um einen zusammengehörigen Zustand anzuzeigen.

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."