Delphi-PRAXiS
Seite 1 von 5  1 23     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi String von Thread an Programm senden - Stilfrage! (https://www.delphipraxis.net/109004-string-von-thread-programm-senden-stilfrage.html)

TheMiller 22. Feb 2008 16:49


String von Thread an Programm senden - Stilfrage!
 
Hallo,

ich habe einen Thread, der einen String an die Hauptform senden soll. Da es sich nur um einen String handelt, möchte ich kein WM_COPYDATA verwenden. Nun habe ich eine Lösung gefunden, frage mich aber, ob diese "sauber" genug ist. Gerne nehme ich Verbesserungsvorschläge an!

Das Prinzip ist folgendes: Ich habe in der Hauptanwendung eine globale Stringvariable. Den Pointer übergebe ich an den Thread. Dieser erstellt einen String und greift direkt auf den Pointer zu und verändert die Variable. (Es ist sichergestellt, dass sich an dem Pointer und an der Inhalt der Variable in dieser Zeit nichts ändert). Danach kann ich normal auf diese Variable zugreifen. Ist das so in Ordnung?

Delphi-Quellcode:
var
  s_thread: String;

..
..

procedure TForm1.Button1Click(Sender: TObject);
var
  Th: TMyThread;
begin
  Th: TMyThread.Create(True);
  Th.s:=@s_thread;
  Th.resume;
end;

Delphi-Quellcode:
procedure TMyThread.Execute;
var
  str: String;
begin
  str:='Hallo, ich bin ein Test';
  s^:=str;
end;
Danke im Voraus

sirius 22. Feb 2008 18:15

Re: String von Thread an Programm senden - Stilfrage!
 
Nö, das geht so nicht.
Du musst schon das schreiben Synchronisieren und nicht nur den Zeiger auf den String kopieren.
Du kannst:

1. Anstatt WM_CopyData auch jede andere Message nehmen und synchronisiert (sendmessage) nen pointer auf die Adresse senden. Wobei das mit dem pointer nicht notwendig ist (Message alleine reicht), da in dem Moment auch der MainThread auf alle public Felder und Properties des TThreads zugreifen kann. Dein Thread wird ja aufgrund des sendmessage angehalten.

2. Du rufst mittels synchronize eine Methode des MainThreads auf und kannst von da auf die gesamte Klasse TThread zugreifen.

3. Eine Schöne Idee ist auch für solche "globalen" AustauschVariablen eine Klasse zu schaffen:
Delphi-Quellcode:
uses sysutils, classes;

type TContainer=class(TMultiReadExclusiveWriteSynchronizer) //oder =class(TSimpleRWSync)
       private
         FmyVariable:string;
         FOnChange:TNotifyEvent; //Vielleicht hier auch eine Liste
         function getmyVariable:string;
         procedure setmyVariable(value:string);
         function getOnChange:TNotifyEvent;
         procedure setOnChange(value:TNotifyEvent);
         procedure DoOnChange;
       public
         property myVariable:string read getmyVariable write setmyVariable;
         property OnChange:TNotifyEvent read getOnChange write setonchange;
     end;




implementation

function Tcontainer.getmyVariable:string;
begin
  beginread;
  result:=FmyVariable;
  endread;
end;
procedure TContainer.setmyVariable(value:string);
begin
  beginwrite;
  FmyVariable:=value;
  endwrite;
  DoOnChange;
end;
function Tcontainer.getOnChange:TNotifyEvent;
begin
  beginread;
  result:=FOnChange;
  endread;
end;
procedure Tcontainer.setOnChange(Value:TNotifyEvent);
begin
  beginwrite;
  FOnChange:=Value;
  endwrite;
end;
procedure Tcontainer.DoOnChange;
var tempOnChange:TNotifyEvent;
begin
  tempOnChange:=OnChange;
  if assigned(tempOnChange) then TempOnChange(self);
end;
Das Konzept habe ich selber noch nie angewandt, aber es wäre auch eine Möglichkeit. Mit Messages muss man ja auch mächtig aufpassen, dass man keine Threads gegenseitig locked. Das Problem hast du damit nicht. Intern wird hier mit Events gearbeitet.
Alternativ kannst du dieselbe Klasse auch von "TSimpleRWSync" ableiten. SimpleRWSync ist, wenn du paralleles Lesen von Threads eher selten hast. Dadurch wird die ganze Klasse etwas schneller. SimpleRWSync kapselt CriticalSections.

TheMiller 22. Feb 2008 18:20

Re: String von Thread an Programm senden - Stilfrage!
 
Ok... meine Lösung hatte zwar funktioniert, aber wenn du davon abrätst ist das ok.

Ich habe jetzt auch gesehen, dass ich direkt von der Anwendung einen String an den Thread schicken kann. Ich dachte das würde auch zu Fehlern wie bei der Stringübergabe zwischen DLL und EXE kommen. Doch das ist nicht so.

Also sende ich einen String vom MainThread an den eigentlichen Thread via globaler Variable und durch sendmessage wieder zurück. Das dürfte das ok sein, oder?

Da es sich nur um eine einzige Variable handelt, bin ich mit der jetzigen Lösung zufrieden. So können doch keine Fehler auftreten, oder?

sirius 22. Feb 2008 18:33

Re: String von Thread an Programm senden - Stilfrage!
 
Zitat:

Zitat von DJ-SPM
Ok... meine Lösung hatte zwar funktioniert, aber wenn du davon abrätst ist das ok.

Diese Fehler treten ja auch erst beim Kunden auf :zwinker: Das Problem besteht ja auch erst, wenn du zufällig zur gleichen Zeit aus mehreren Threads darauf zugreifst (und mindestens ein Thread schreibt )

Zitat:

Zitat von DJ-SPM
Ich habe jetzt auch gesehen, dass ich direkt von der Anwendung einen String an den Thread schicken kann. Ich dachte das würde auch zu Fehlern wie bei der Stringübergabe zwischen DLL und EXE kommen. Doch das ist nicht so.

Jep, ist ja auch derselbe Speichermanager.

Zitat:

Zitat von DJ-SPM
Also sende ich einen String vom MainThread an den eigentlichen Thread via globaler Variable und durch sendmessage wieder zurück. Das dürfte das ok sein, oder?

Aber achte darauf, dass du sendmessage nur in eine Richtung verwenden darfst. Also nur ein Thread darf an den anderen mittels sendmessage etwas schicken. Zurück geht es nicht. Aber du kannst, wie gesagt, in der Messagebearbeitungsroutine schreibend und lesend auf alle Felder der Klasse zugreifen.
Delphi-Quellcode:
procedure TThread.execute;
begin
...
  self.s:='Hallo';
  sendmessage(mainhandle,WM_threadsomething,0,0);
  //jetzt beinhaltet self.s einen neuen Wert
  ...
end;

procedure TForm1.getThreadMessage(var msg:TMessage); //message WM_threadsomething
begin
  //Da der Thread jetzt schläft, kannst du ohne Risiko auf alle Variablen des threads zugreifen
  showmessage(Thread.s);
  Thread.s:='gelesen';
end;
Zitat:

Zitat von DJ-SPM
Da es sich nur um eine einzige Variable handelt, bin ich mit der jetzigen Lösung zufrieden. So können doch keine Fehler auftreten, oder?

Ja, das ist auch mein Stil. (aber es gibt bestimmt einige hier, die dich dafür verhauen würden. :mrgreen:)

alzaimar 22. Feb 2008 18:36

Re: String von Thread an Programm senden - Stilfrage!
 
Eins der immer noch gültigen Grundprinzipien modularer Programmierung sind die Datenmodule. Hinter diesem Konzept verbergen sich Container, die Daten enthalten, die von den Modulen gemeinsam benutzt und verändert werden. Daher hat Delphi auch das TDatamodule-Konzept, obwohl das hier nur konzeptionell vergleichbar ist: Also jetzt nicht an TDatamodule denken.

Anders ausgedrückt sollt Du dich schnellstmöglich von der Methapher 'Senden von Daten' verabschieden. Die Daten sind irgendwo in einem Datenmodul und da sind sie auch gut aufgehoben. Die der Vorschlag von Sirius geht ja genau in diese Richtung.

Du hast also 'Container' (Datenmodule), die die Daten speichern und über geeignete Methoden sicherst Du konfliktfreien Zugang ztu den Daten.

Deine Threads verändern also asynchron diese Daten und teilen dann anderen Threads mit, das die Arbeit beendet ist, und die Weiterverarbeitung starten kann. Ob man das mit Messages oder Events löst, bleibt Dir überlassen.

Du könntest Dir auch vorstellen, das ein Thread immer einen Teil abarbeitet, dann einem 2.Thread mitteilt, das es etwas zu tun gibt. Der macht dann weiter, während sich Thread#1 wieder um den nächsten Happen kümmert usw. Dabei werden keine Daten verschickt, sondern nur Nachrichten.

Wenn Du an Anwendungsentwicklung im Team denkst, wird Code ja auch gemeinsam über ein CVS verwaltet und nicht immer komplett versendet...

TheMiller 22. Feb 2008 18:42

Re: String von Thread an Programm senden - Stilfrage!
 
Vielen Dank für eure Mühe, doch der letzte Beitrag hat mich nun wieder verunsichert? Ist die aktuelle Methode, dich ich oben beschrieben habe und auch nutze, jetzt verwendbar oder nicht. Das konnte ich jetzt nicht rauslesen. :oops:

Zitat:

Zitat von Ich
Also sende ich einen String vom MainThread an den eigentlichen Thread via globaler Variable und durch sendmessage wieder zurück. Das dürfte das ok sein, oder?


sirius 22. Feb 2008 19:31

Re: String von Thread an Programm senden - Stilfrage!
 
Verwendbar (mit genannten Einschränkungen) ist sie. aber du kannst eben auch OOP-konformer arbeiten. Dadurch gewöhnst du dir gleich die richtige Arbeitsweise an.
Du kannst zum Beispiel die Klasse TCotainer im Mainthread instanzieren und dann die Instanz an den Thread übergeben. Und hier kannst du problemlos auf die Propertys zugreifen und ich habe auch ein OnChange Ereignis eingebaut. diese beginwrite und endwrite (sowie *read) Abschnitte verhindern eben das gleichzeitige Schreiben mehrere Threads.

TheMiller 22. Feb 2008 19:52

Re: String von Thread an Programm senden - Stilfrage!
 
Hm...ich weis nicht ob ich das alles gerade richtig verstanden habe... Was würde bei meiner Lösung passieren, wenn ich mehrere Threads gleichzeit hätte (warum auch immer)?

alzaimar 22. Feb 2008 20:22

Re: String von Thread an Programm senden - Stilfrage!
 
Na durch die Kapselung der Zugrissmethoden machst Du deinen Container (altdeutsch 'Datenmodul') ja ggf. threadsicher. Das ist doch gerade das Gute an so einem Container bzw. der ganzen OOP-Chose. Wie Du genau den Zugriff auf die Daten implementierst (Datenbank, synchronisiert oder ob Du sie immer life vom Mond holst) ist gekapselt. Da man gar nicht mehr direkt an die Rohdaten herankommt, musst Du dir nie wieder Gedanken über Threadsicherheit machen (sofern Du den Zugriff eben synchronisierst).

Befolge doch einfach sirius' Rat, instantiiere den Container und übergebe dem Thread diese Instanz. Der Zugriff auf die konkreten Daten ist doch threadsicher.

TheMiller 22. Feb 2008 20:27

Re: String von Thread an Programm senden - Stilfrage!
 
Ok, jetzt habe ich glaub ich verstanden. Ich werde die Lösung einbauen. Komme aber erst wieder am Sonntag dazu.

Danke für eure Hilfe / Geduld!


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:21 Uhr.
Seite 1 von 5  1 23     Letzte »    

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz