![]() |
QueueUserWorkItem wie sieht es in Delphi aus?
Die Funktion ist so deklariert:
Code:
Mit welchem Datentyp übersetzt man den ersten Parameter in Delphi?
BOOL QueueUserWorkItem(
LPTHREAD_START_ROUTINE Function, PVOID Context, ULONG Flags ); Im PSDK steht noch dazu: Zitat:
|
Re: QueueUserWorkItem wie sieht es in Delphi aus?
OK, ich habs jetzt. Mein Beispielprogramm sieht jetzt so aus:
Delphi-Quellcode:
Allerdings habe ich da noch ein Verständnisproblem oder so:
type
TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } i: Cardinal; public { Public declarations } end; type TThreadParams = record ThreadID: Cardinal; end; PThreadParams = ^TThreadParams; var Form1 : TForm1; function QueueUserWorkItem(LPTHREAD_START_ROUTINE: Pointer; Context: Pointer; Flags: DWORD): DWORD; stdcall; external 'kernel32.dll'; const WT_EXECUTEDEFAULT = $00000000; WT_EXECUTEINIOTHREAD = $00000001; WT_EXECUTEINUITHREAD = $00000002; WT_EXECUTEINWAITTHREAD = $00000004; WT_EXECUTEONLYONCE = $00000008; WT_EXECUTEINTIMERTHREAD = $00000020; WT_EXECUTELONGFUNCTION = $00000010; WT_EXECUTEINPERSISTENTIOTHREAD = $00000040; WT_EXECUTEINPERSISTENTTHREAD = $00000080; WT_TRANSFER_IMPERSONATION = $00000100; implementation {$R *.dfm} function Thread(p: Pointer): Integer; var hWnd: THandle; ThreadID: Cardinal; begin ThreadID := PThreadParams(p)^.ThreadID; Messagebox(0, PChar(IntToStr(ThreadID)), '', 0); Dispose(p); result := 0; end; procedure TForm1.Button1Click(Sender: TObject); var ThreadParams: PThreadParams; begin New(ThreadParams); ThreadParams.ThreadID := i; if QueueUserWorkItem(@Thread, ThreadParams, WT_EXECUTEONLYONCE) = 0 then ShowMessage(SysErrorMessage(GetLastError)); Inc(i); end; Ich klicke einmal, ich bomme die Messagebox null, ich klicke ein zweites mal, ich bekomme die Messagebox eins, ich klicke ein drittes mal, es passiert nichts, ich klicke ein viertes mal, es passiert nichts, ich klicke ein fünftes mal, ich bekomme die Messagebox drei. Entsprechd wird auch nur die Anzahl der Threads im Taskmanager erhöht. Aber sollte es nicht so sein, dass bei jedem Aufruf von QueueUserWorkItem ein Thread erzeugt wird? Oder wie soll das funktionieren? |
Re: QueueUserWorkItem wie sieht es in Delphi aus?
Zitat:
|
Re: QueueUserWorkItem wie sieht es in Delphi aus?
Ein einfacher Pointer tut es auch, wie man sieht. ;) Aber ich hätte jetzt gerne noch Aufklärung über das Funktionsprinzip. :gruebel:
|
Re: QueueUserWorkItem wie sieht es in Delphi aus?
die Calling-Convention deiner Thread-Funktion stimmt übrigens nicht; richtig wäre StdCall:
Delphi-Quellcode:
function Thread(p: Pointer): Integer; StdCall;
|
Re: QueueUserWorkItem wie sieht es in Delphi aus?
WT_EXECUTEONLYONCE steht bei MS nicht in der Liste der für QueueUserWorkItem gültigen Flags...
|
Re: QueueUserWorkItem wie sieht es in Delphi aus?
@Basilikum: Das ändert nichts am Verhalten.
@Union: Ist aber in WinNT.h deklariert. Aha, so gehts:
Delphi-Quellcode:
stdcall und WT_EXECUTELONGFUNCTION zusammen erzeugen jedes mal einen neuen Thread.
function Thread(p: Pointer): Integer; stdcall;
var ThreadID: Cardinal; begin ThreadID := PThreadParams(p)^.ThreadID; Messagebox(0, PChar(IntToStr(ThreadID)), '', 0); Dispose(p); result := 0; end; procedure TForm1.Button1Click(Sender: TObject); var ThreadParams: PThreadParams; begin New(ThreadParams); ThreadParams.ThreadID := i; if QueueUserWorkItem(@Thread, ThreadParams, WT_EXECUTELONGFUNCTION) = 0 then ShowMessage(SysErrorMessage(GetLastError)); Inc(i); end; Aber hilft mir das bei folgendem Szenario: Ich habe einen Server zum dem verbinden sich Clients. Es sollen maximal fünf Client-Threads laufen. das heißt, wenn fünf Thread schon existieren, soll es keinen neuen mehr geben, sondern der sechste Cliuent soll sich erst verbinden können, wenn einer der ersten fünf Clients sich wieder verabschiedet hat. Wenn sich das mit QueueUserWorkItem machen läßt, wie löst man das problem am besten? Laut PSDK soll das ja möglcih sein: Zitat:
|
Re: QueueUserWorkItem wie sieht es in Delphi aus?
Zitat:
|
Re: QueueUserWorkItem wie sieht es in Delphi aus?
Ich weiß, ich spame, aber ich habe es gerade gefunden:
Delphi-Quellcode:
Übergibt man als Flag: WT_EXECUTEDEFAULT ergibt sich obige Situation: Dass Messagebox zwei nicht erscheint. Schließe ich eine alte Messagebox, erscheint Mesaagebox zwei, ohne dass ich noch mal auf die Schaltfläche geklickt habe. Tut also alles, wie es soll. ;)
procedure TForm1.Button1Click(Sender: TObject);
var ThreadParams: PThreadParams; begin New(ThreadParams); ThreadParams.ThreadID := i; if QueueUserWorkItem(@Thread, ThreadParams, WT_EXECUTEDEFAULT) = 0 then ShowMessage(SysErrorMessage(GetLastError)); Inc(i); end; Fällt jemanden jetzt dazu eine schöne Demoanwendung ein? |
Re: QueueUserWorkItem wie sieht es in Delphi aus?
Zitat:
Zitat:
|
Re: QueueUserWorkItem wie sieht es in Delphi aus?
Die erste Lösung klingt doch schon mal gut. Besten Dank.
Sollte das dann so aussehen?
Delphi-Quellcode:
Weil das funktioniert irgendwie nicht:
QueueUserWorkItem(@Thread, ThreadParams, WT_EXECUTELONGFUNCTION or 2 * $10000)
Delphi-Quellcode:
Es werden doch alle sech Listboxen gleichzeitig ausgefüllt. Und ohne das Sleep(10) kommt er sogar durcheinander und füllt die letzte mehrmals aus.
function Thread(p: Pointer): Integer; stdcall;
var LBIndex : Cardinal; Cnt : Cardinal; begin LBIndex := PThreadParams(p)^.LBIndex; for cnt := 0 to 99 do begin TListbox(Form1.FindComponent('Listbox' + IntToStr(LBIndex))).Items.Add(IntToStr(cnt)); sleep(50); end; result := 0; end; procedure TForm1.Button1Click(Sender: TObject); var ThreadParams : PThreadParams; i : Integer; begin New(ThreadParams); for i := 1 to 6 do begin sleep(10); ThreadParams.LBIndex := i; if QueueUserWorkItem(@Thread, ThreadParams, WT_EXECUTELONGFUNCTION or 2 * $10000) = 0 then ShowMessage(SysErrorMessage(GetLastError)); end; end; |
Re: QueueUserWorkItem wie sieht es in Delphi aus?
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habe mal eine bessere Demoanwendung geschrieben:
Sie besteht aus einem Empfänger und einem Sender. Der Sender schickt eine Anforderung an den Empfänger, der daraufhin eine Listbox füllen soll. Auf dem Empfänger-Formular befinden sich sechs Listboxen, der Sender gibt dem Empfänger jeweils mit, welche Listbox gefüllt werden soll. Der Empfänger erzeugt dann entweder, je nach Auslastung, einen neuen Thread im Thread-Pool oder wartet bis ein Thread fertig ist und die Anforderung übernehmen kann. Klicke ich zum Beispiel vier mal auf die Schaltfläche des Senders werden erst zwei Listboxen gefüllt und die verbleibenden zwei erst, wenn die Threads der ersten zwei Listboxen fertig sind. Dabei sollte man immer mal die Statusleiste des Empfängers beobachten, die die Anzahl der Threads anzeigt und gucken, wie die Listboxen gefüllt werden. Und wartet man bis die ersten Threads fertig sind und sendet dann eine weitere Anforderung, wird man sehen, dass keine weiteren Threads im Thread-Pool erzeugt werden. Dann sollte man mal den Flag WT_EXECUTEDEFAULT durch den Flag WT_EXECUTELONGFUNCTION austauschen und wieder das Verhalten des Empfängers beobachten. WT_EXECUTELONGFUNCTION teilt dem System mit, dass der aufgerufene Thread etwas länger braucht bis er zurückkehrt, was das Erstellen von neuen Threads im Thread-Pool durch das System beeinflusst. Es neigt dann nämlich eher dazu einen neuen Thread zu starten. Die Anzahl der Threads soll man so:
Delphi-Quellcode:
beeinflussen können. In diesem Fall sollten jetzt nur maximal fünf Threads gestartet werden. Bei mir hat das aber noch nicht so ganz geklappt, glaube ich.
QueueUserWorkItem(@Thread, ThreadParams, WT_EXECUTEDEFAULT or 5 + $10000)
Demo im Anhang. |
Re: QueueUserWorkItem wie sieht es in Delphi aus?
Zitat:
|
Re: QueueUserWorkItem wie sieht es in Delphi aus?
Ah, OK, also kann man es nicht so beeinflussen, wie ich dachte, dass man es könnte. Kann man eigentlich die Threads wieder irgendwie aus dem Thread-Pool löschen? Oder hängen die jetzt bis zum Prozessende da drinn? Verbrauchen die eigentlich Ressourcen im Thread-Pool?
|
Re: QueueUserWorkItem wie sieht es in Delphi aus?
Es empfiehlt sich die Jedi-Apilib zu verwenden (JwaWinBase.pas).
![]() Dort ist die Funktion mit einem korrekten Typen fuer den Callbackparameter deklariert. Wer den Zugriff auf das CVS nicht scheut der bekommt jetzt auch noch ein JwaWindows.pas das die einzelnen Teilfiles per Include vereinigt. |
Re: QueueUserWorkItem wie sieht es in Delphi aus?
Danke für den Hinweis, das beantwortet aber leider nicht meine abschließende Frage.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:32 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz