Autor |
Beitrag |
BenBE
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 26.01.16 11:41
Hi,
heut von mir mal in der etwas ungewöhnlicheren Sparte ein Post.
Geht drum, ich habe eine Routine (wenige Zeilen), die auf Grund der darin verwendeten API zwingend auf einem eigenen Thread aufgerufen werden muss.
Für diese Routine muss ich 2 Parameter (Passen jeweils in einen Integer) übergeben.
Der startende Thread (in meinem Fall der Main Thread), soll auf den aufgerufnen Thread warten. Also in etwa:
Vereinfachter Pseudocode: 1: 2: 3: 4: 5: 6: 7:
| { auto thread = NEW_THREAD( [foo, bar]() { } ); thread.start(); thread.waitForExit(); } |
Geht das auch irgendwie, ohne erst groß TThread komisch ableiten zu müssen?
Ach ja: Geht mir nicht um Performance, sondern kurze, übersichtliche Schreibweise.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 26.01.16 16:19
Ich würde TTask verwenden, dieses Beispiel hatte ich dafür schon mal irgendwo gepostet: 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:
| uses System.Threading;
var Tasks: array[0..1] of ITask; a, b, c, d: Integer; begin a := 42; b := 100; Tasks[0] := TTask.Create( procedure() begin Sleep(1000); c := a + b; end); Tasks[0].Start; Tasks[1] := TTask.Create( procedure() begin Sleep(3000); d := b - a; end); Tasks[1].Start; TTask.WaitForAll(Tasks); ShowMessage(IntToStr(c) + ' - ' + IntToStr(d)); |
|
|
BenBE
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 26.01.16 16:47
Irgendwie meckert FPC bei mir bei System.Threading rum (";" erwartet, aber "." gefunden). Unit wird mit {$mode objfpc}{$H+} übersetzt, auch wenn das nicht das Problem sein dürfte.
Ansonsten ist das syntaktisch aber schon genau, wonach ich gesucht hatte
BTW: Lazarus 1.4.4 / FPC 2.6.4 in case it matters here.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 26.01.16 18:00
Dann kann Lazarus das wohl nicht...
Vielleicht heißt die Unit aber auch nur anders. Das Beispiel stammt aus Delphi, ich hatte die Sparte übersehen.
|
|
Martok
Beiträge: 3661
Erhaltene Danke: 604
Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
|
Verfasst: Di 26.01.16 19:35
Warum TThread.CreateAnonymousThread noch keine Nestedprocvars kann ist mir nicht klar, wenn das drin wäre wär's die Antwort. So muss man das kurz selber bauen (das was du suchst ist TNestedThread, der generic steht da nur weil ich mal wissen wollte wie die Syntax dann aussieht):
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:
| unit Unit1;
{$mode objfpc}{$H+} {$ModeSwitch nestedprocvars}
interface
uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private public end;
TNestedThread = class(TThread) public type TRunFunc = procedure is nested; private FFunc: TRunFunc; protected procedure Execute; override; public constructor Create(Func: TRunFunc); end;
generic TDataThread<GData> = class(TThread) public type TRunFunc = procedure (Data: GData); private FData: GData; FFunc: TRunFunc; protected procedure Execute; override; public constructor Create(Data: GData; Func: TRunFunc); end;
var Form1: TForm1;
implementation
{$R *.lfm}
procedure ThrdMethod(I: PInteger); begin I^:= 1337; end;
procedure TForm1.Button1Click(Sender: TObject); var x, y: integer;
procedure ThrdMethodN(); begin X:= 42; Y:= 23; end;
begin TNestedThread.Create(@ThrdMethodN).WaitFor; ShowMessageFmt('x: %d, y: %d', [x, y]);
(specialize TDataThread<PInteger>).Create(@X, @ThrdMethod).WaitFor; ShowMessageFmt('x: %d, y: %d', [x, y]); end;
procedure TNestedThread.Execute; begin FFunc(); end;
constructor TNestedThread.Create(Func: TRunFunc); begin inherited Create(true); FreeOnTerminate:= true; FFunc:= Func; Resume; end;
procedure TDataThread.Execute; begin FFunc(FData); end;
constructor TDataThread.Create(Data: GData; Func: TRunFunc); begin inherited Create(true); FreeOnTerminate:= true; FData:= Data; FFunc:= Func; Resume; end;
end. |
WaitForMultiple etc. überlasse ich mal als einfache Übung dem Leser
Edit: Oh, noch was: in den Mainthread zurück kommst du dann per TThread.Synchronize und .Queue, aber der Deadlock da drin wenn man das im Code oben tut dürfte offensichtlich sein. Die Variante für Nested wäre dann auch noch zu bauen.
_________________ "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."
|
|
BenBE
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mi 27.01.16 13:17
Ist zwar nicht ganz so schön in-lambda-line, wie ich mir das erhofft hab, aber die TNestedThread-Klasse von Martok funzt wie gewünscht. Und Anfang der Methode ist grad noch so akzeptabel
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
|