Entwickler-Ecke
Free Pascal - Thread möglichst elegant
BenBE - Di 26.01.16 11:41
Titel: Thread möglichst elegant
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.
jaenicke - 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 - 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.
jaenicke - 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 - 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):
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:
| 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.
BenBE - 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 ;-)
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!