Entwickler-Ecke

Windows API - Deadlock bei Tab öffnen und schließen im Thread


AgeArtmann - Mi 07.11.07 00:33
Titel: Deadlock bei Tab öffnen und schließen im Thread
Hallo,

Hab hier eine Deadlocksituation an der ich mir die Zähne ausbeiße
bin schon lange am tüfteln, komme aber einfach nicht drauf.

Hat jemand von euch eine Idee?


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:
procedure TDownload.Execute;
var
  TempTabSheet:TTabSheet;
begin
  CoInitialize(nil);
  try
    age_cs.Enter;
    //kritischer Prozess Begin
    TempTabSheet:= CreateTabBrowser('about:blank''TAB');
  finally
    age_cs.Leave;
  end;

  try
    age_cs.Enter;
    //kritischer Prozess Begin
    TempTabSheet.Free;
  finally
    age_cs.Leave;
  end;

  CoUnInitialize;
end;


age_cs ist auch initialisiert:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
initialization
  OleInitialize(nil);
  CoInitialize(nil);
  age_cs := TCriticalSection.Create;
finalization
  OleUninitialize;
  CoUninitialize;
  age_cs.Free;
end.



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:
function CreateTabBrowser(sURL, sCaption: string): TTabSheet;
var
  ts: TTabSheet;
  WB: TWebbrowser;
begin
  // Create a new TabSheet
  ts := TTabSheet.Create(PageControl);
  Result := ts;
  try
    // Assign TTabSheet Properties
    ts.PageControl := PageControl;
    ts.Parent := PageControl;
    ts.Caption := sCaption;
    //ts.PageIndex := PageControl.ActivePageIndex + 1;

    // Create a TWebbrowser instance
    WB := TWebbrowser.Create(ts);

    // put TWebbrowser on TTabSheet
    TControl(WB).Parent := ts;
    // or:   Ts.InsertControl(WB);

    // Assign Webbrowser Properties
    WB.Align := alClient;
    WB.Silent := True;
    WB.Visible := True;

    PageControl.ActivePage := ts;

    // Assign Webbrowser Events
    //WB.OnProgressChange := WebBrowser1ProgressChange;
    //WB.OnStatusTextChange := WebBrowser1StatusTextChange;
    //WB.OnTitleChange := WebBrowser1TitleChange;
    WB.OnNewWindow2 := Form1.WebBrowser_Tab_NewWindow2;
    //WB.OnCommandStateChange := WebBrowser1CommandStateChange;
    //WB.OnDownloadComplete := WebBrowser1DownloadComplete;
    //WB.OnDocumentComplete := WebBrowser1DocumentComplete;
    //WB.OnDownloadBegin := WebBrowser1DownloadBegin;
    //WB.FNavForward := False;
    //WB.FNavBack := False;

    // Navigate to a URL
    if Trim(sURL) <> '' then
    begin
      WB.Navigate(sURL);
      WB_Warten_spec(WB,0);
    end;
  except
    ts.Free;
    Log('Fehler beim Tab createn',3);
  end;
end;


Wenn ich nun Versuche 10 Threads zu starten hängt er sich nach dem 2. Tab auf


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TForm1.Button15Click(Sender: TObject);
var
  j:Integer;
  DownloadThreads: array [0..9of TDownload;
begin
// die ersten 10 threads starten
  for j := 0 to 9 do
  begin
    DownloadThreads[j] := TDownload.Create(True);
    DownloadThreads[j].FreeOnTerminate := True;
    DownloadThreads[j].Index := j;
    DownloadThreads[j].Resume;
  end;
end;



Ich hab irgendwie das Gefühl er ignoriert die CriticalSection und überschneidet das Erstellen und schließen der Tabs

Vielen Dank im Voraus

MfG AgeArtmann


alzaimar - Mi 07.11.07 09:01

VCL-Komponenten sollen nicht in einem Thread angesprochen werden. Das funktioniert einfach nicht. Die visuellen Komponenten dürfen nur im Kontext des Hauptthreads manipuliert werden.

Hierzu eignet sich die Synchronize-Methode der TThread-Klasse.

Anstatt:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
Procedure TMyThread.Execute;
Begin
  ...
  MainForm.Control.Caption := 'Foobar'// <<--- Zugriff auf VCL, hier wird der Thread hängen bleiben
  ...
End;

Musst Du sowas machen;

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
Procedure TMyThread.DoUpdateControl;
Begin
  MainForm.Control.Caption := 'Foobar'// <<--- Zugriff auf VCL
End;

Procedure TMyThread.Execute;
Begin
  ...
  Synchronize (DoUpdateControl);        // <<--- So klappts
  ...
End;

Das ist ein bisserl umständlich und auch häßlich, lässt sich aber nicht vermeiden.