Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi QueueUserWorkItem wie sieht es in Delphi aus? (https://www.delphipraxis.net/53491-queueuserworkitem-wie-sieht-es-delphi-aus.html)

Luckie 17. Sep 2005 16:32


QueueUserWorkItem wie sieht es in Delphi aus?
 
Die Funktion ist so deklariert:
Code:
BOOL QueueUserWorkItem(
  LPTHREAD_START_ROUTINE Function,
  PVOID Context,
  ULONG Flags
);
Mit welchem Datentyp übersetzt man den ersten Parameter in Delphi?

Im PSDK steht noch dazu:
Zitat:

[in] Pointer to the application-defined callback function of type LPTHREAD_START_ROUTINE to be executed by the thread in the thread pool. This value represents the starting address of the thread. This callback function must not call the TerminateThread function.
For more information, see ThreadProc.
Google war diesmal irgendwie nicht sehr hilfreich. :-?

Luckie 17. Sep 2005 16:57

Re: QueueUserWorkItem wie sieht es in Delphi aus?
 
OK, ich habs jetzt. Mein Beispielprogramm sieht jetzt so aus:
Delphi-Quellcode:
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;
Allerdings habe ich da noch ein Verständnisproblem oder so:
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?

Union 17. Sep 2005 17:09

Re: QueueUserWorkItem wie sieht es in Delphi aus?
 
Zitat:

Zitat von Luckie
Die Funktion ist so deklariert:
Code:
BOOL QueueUserWorkItem(
  LPTHREAD_START_ROUTINE Function,
  PVOID Context,
  ULONG Flags
);
Mit welchem Datentyp übersetzt man den ersten Parameter in Delphi?

Im PSDK steht noch dazu:
Zitat:

[in] Pointer to the application-defined callback function of type LPTHREAD_START_ROUTINE to be executed by the thread in the thread pool. This value represents the starting address of the thread. This callback function must not call the TerminateThread function.
For more information, see ThreadProc.
Google war diesmal irgendwie nicht sehr hilfreich. :-?

Wie wärs denn mit @MyThreadStartFunction ? Aufbau dieser Funktion wie ThreadProc.

Luckie 17. Sep 2005 17:13

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:

Basilikum 17. Sep 2005 17:22

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;

Union 17. Sep 2005 17:32

Re: QueueUserWorkItem wie sieht es in Delphi aus?
 
WT_EXECUTEONLYONCE steht bei MS nicht in der Liste der für QueueUserWorkItem gültigen Flags...

Luckie 17. Sep 2005 17:51

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:
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;
stdcall und WT_EXECUTELONGFUNCTION zusammen erzeugen jedes mal einen neuen Thread.

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:

There are many applications that create threads that spend a great deal of time in the sleeping state waiting for an event to occur. Other threads may enter a sleeping state only to be awakened periodically to poll for a change or update status information. Thread pooling enables you to use threads more efficiently by providing your application with a pool of worker threads that are managed by the system. At least one thread monitors the status of all wait operations queued to the thread pool. When a wait operation has completed, a worker thread from the thread pool executes the corresponding callback function.
Ich erzeuge als gleich fünf Threads und wenn ein Client kommt wird ein Thread aus dem ThreadPool genommen, der ihn bedient. Fällt jemanden dazu eine kleine Demo Anwendung ein?

Flocke 17. Sep 2005 18:10

Re: QueueUserWorkItem wie sieht es in Delphi aus?
 
Zitat:

Zitat von Luckie
@Basilikum: Das ändert nichts am Verhalten.

Das stimmt natürlich nicht. Bei der Standardaufrufkonvention "register" wird der erste Parameter in EAX übergeben, bei "stdcall" auf dem Stack. Du hast also einfach "Glück" wenn's trotzdem funktioniert.

Luckie 17. Sep 2005 18:11

Re: QueueUserWorkItem wie sieht es in Delphi aus?
 
Ich weiß, ich spame, aber ich habe es gerade gefunden:
Delphi-Quellcode:
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;
Ü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. ;)

Fällt jemanden jetzt dazu eine schöne Demoanwendung ein?

Union 17. Sep 2005 18:12

Re: QueueUserWorkItem wie sieht es in Delphi aus?
 
Zitat:

Zitat von Luckie
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?

Maximale Anzahl Threads setzt Du, indem Du auf die Flags MaxThreads * $10000 addierst:

Zitat:

Zitat von MSDN
By default, the thread pool has a maximum of 512 threads per process. To raise the queue limit, use the WT_SET_MAX_THREADPOOL_THREAD macro defined in Winnt.h.


#define WT_SET_MAX_THREADPOOL_THREADS(Flags,Limit) ((Flags)|=(Limit)<<16)

Alternativ kannst Du auch mit Mutexen arbeiten oder einen Zähler im steuernden Prozess verwenden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:19 Uhr.
Seite 1 von 2  1 2      

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