![]() |
W1000 Symbol 'Resume' ist veraltet ????
Hallo,
bei einem Projekt in dem ich Threads verwende kommt jetzt mit D 2010 folgende Warnung: Zitat:
Ist das ein Bug in D 2010? Gruß Klaus. |
Re: W1000 Symbol 'Resume' ist veraltet ????
Delphi-Quellcode:
Was ein Blick in die Sourcen so leisten kann. :angel2:
// This function is not intended to be used for thread synchronization.
procedure Resume; deprecated; // Use Start after creating a suspended thread. procedure Start; // This function is not intended to be used for thread synchronization. procedure Suspend; deprecated; |
Re: W1000 Symbol 'Resume' ist veraltet ????
Also wenn man bei Delphi selber guckt, steht dies im Source:
Delphi-Quellcode:
// This function is not intended to be used for thread synchronization.
procedure Resume; deprecated; // Use Start after creating a suspended thread. procedure Start; |
Re: W1000 Symbol 'Resume' ist veraltet ????
Danke an euch.
Also ein Bug der Online-Hilfe. Denn da steht: Zitat:
Zitat:
|
AW: W1000 Symbol 'Resume' ist veraltet ????
Ich sehe Suspend ist veraltet...
aber was verwenden an stelle dessen? Werde aus euren Beiträgen nicht so richtig schlau. OK für Resume nehme ich Start.. aber für Suspend ? EDIT: Terminate? gruss |
AW: W1000 Symbol 'Resume' ist veraltet ????
Suspend sollte man ganz vermeiden, da man nie wissen kann in welchem Augenblick man den Thread damit erwischt - schwer zu findende Deadlocks sind so vorprogrammiert. Besser Terminate oder ein eigenes Flag(Boolean/Event/Semaphore..) verwenden um den Thread ggf. an einer kontrollierten Stelle warten zu lassen.
|
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
bzw. Resume mit Start dann geht bei mir gar nichts mehr. Hmmmm ... Dann besser so belassen und mit den Warnungen leben? gruss |
AW: W1000 Symbol 'Resume' ist veraltet ????
Hmm.. wenn property Terminated wie in älteren Versionen ReadOnly ist und .Start das scheinbar auch nicht zurücksetzt ist es natürlich keine Lösung - dann kann man den Thread auch freigeben und einen neuen erzeugen.. das Konzept scheint mal wieder sehr gut durchdacht zu sein :?
Idee:
Delphi-Quellcode:
Zu jedem "Terminate" gehört dann natürlich ein "Continue" um den Thread ggf. aufzuwecken.
type
TMyThread = class(TThread) private FHalted: Boolean; procedure SuspendIfHalted; public procedure Halt; procedure Continue; end; procedure TMyThread.Halt; begin FHalted := True; end; procedure TMyThread.Continue; begin FHalted := False; ResumeThread(Handle); end; procedure TMyThread.SuspendIfHalted; begin if FHalted then SuspendThread(Handle); end; procedure TMyThread.Execute; begin repeat EntercriticalSection; .. LeaveCriticalSection; .. //sichere Warteposition ausserhalb Lock SuspendIfHalted; until Terminated; end; Alternativ zu SuspendIfHalted ohne echtes Suspend-/ResumeThread:
Delphi-Quellcode:
while FHalted and not Terminated do Sleep(10);
Grüsse, Dirk |
AW: W1000 Symbol 'Resume' ist veraltet ????
Danke für dein Beispiel .. Werde mir das mal anschauen in Ruhe.
Mein Problem ist folgendes
Delphi-Quellcode:
So wie hier wartest du auch auf Terminate..
procedure TMyThread.Execute;
begin repeat EntercriticalSection; .. LeaveCriticalSection; .. //sichere Warteposition ausserhalb Lock SuspendIfHalted; until Terminated; end; Der Thread läuft also so lange bis der Zustand Terminate eintritt. Wenn ich nun anstelle von Suspend.. Terminate verwende so wie vorgeschlagen dann beendet sich logischerweise der Thread das hat zur folge das ich anschließend kein Plugin mehr starten kann. MeinThread.Suspend hält den Thread ja nur an und beendet ihn nicht so wie Terminate das tut. Damit stehe ich im Konflikt zu der Aussage anstelle von Suspend! Terminate zu verwenden. Na ja und wie MeinThread.Start im vergleich zu MeinThread.Resume steht das ist auch noch fraglisch. gruss |
AW: W1000 Symbol 'Resume' ist veraltet ????
Das Suspend würde ich nicht durch Terminate ersetzen, das funzt halt einfach nicht.
Das "gefähliche" Suspend von aussen würde ich halt vermeiden indem ich nur ein Flag setze über welches der Thread sich zu einem sicheren Zeitpunkt (wenn er gerade nichts blockiert) selber unterbricht. Das Fortsetzen (ResumeThread) ist dann unkritisch. Grüsse, Dirk |
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
aber keine Anwendbare lösung dafür zur verfügung stellt. Werd wohl nicht drum rum kommen da selbst was zu basteln. Danke. gruss |
AW: W1000 Symbol 'Resume' ist veraltet ????
Naja, die ganze Konstruktion mit Suspend und Resume war eben potentiell gefährlich.
Deshalb ist es besser da etwas individuell auf den konkreten Fall angepasst zu schreiben als etwas einfaches zu nutzen, das zu schwer zu findenden massiven Problemen (wie schon genannt Deadlocks) führen kann. Zumal man den Ablauf dabei auch gleich viel besser optimieren kann. |
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
Delphi-Quellcode:
Wobei die D2010-OH diesbezüglich wirklich schrottig ist,
// This function is not intended to be used for thread synchronization.
procedure Resume; deprecated; // Use Start after creating a suspended thread. procedure Start; // This function is not intended to be used for thread synchronization. procedure Suspend; deprecated; denn bei ![]() ![]() aber bei ![]() Zitat:
Außerdem gehört eine Erklärung in die OH, warum diese sooo gefährlich und nun auch deprecated sind. [add] OK, in XE hat man dieses ja nun endlich mal beseitigt. (schön, daß "alte" Versionen so selten geupdatet werde) Zitat:
|
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
gruss |
AW: W1000 Symbol 'Resume' ist veraltet ????
Statt .Resume nutzt man jetzt .Start
und .Suspend gibt es nicht mehr ... auch keinen Ersatz dafür. Zum Anhalten kannst du ein Event, eine CriticalSection oder sonstwas verwenden, welches den Thread an einer definierten Stelle anhält und dir bescheid gibt, wenn angehalten wurde. OK, es wäre ja schön gewesen, wenn Emba solche Funktionen gleich eingebaut hätte und man es nicht selber implementieren müßte. |
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
Geben tut es das schon noch man soll es halt möglichst nicht mehr verwenden. Einen Ansatz einer möglichen Lösung hat Tryer ja schon gepostet (danke) Prüfe gerade ob man es für jede auftretende Sitution verwenden kann. PS: Das mit Suspend erklärt vielleicht meine sporadisch auftretenden hänger wenn ich von einem zum anderen Plugin schalte. Edit: Also das mit Start kannst auch vergessen auch kein ersatz für Resume. Zitat:
|
AW: W1000 Symbol 'Resume' ist veraltet ????
Aber bitte auch nicht SuspendThread nehmen. Ist ja nur der API Aufruf, der in TThread.Suspend gekapselt wird. Auch msdn schreibt, dass man SuspendThread nur zum Debuggen nehmen soll. Allerdings steht nirgends etwas darüber, warum man SuspendThread nicht aus dem eigenen Thread heraus aufrufen kann. Dennoch gibt es schönere / andere Methoden:
Delphi-Quellcode:
{ TmyThread }
private FHaltEvent:TEvent; //... procedure TmyThread.Continue; begin FHaltEvent.SetEvent; end; constructor TmyThread.Create(aSuspended: boolean); begin inherited; FHaltEvent:=TEvent.Create(nil,true,true,''); end; destructor TmyThread.Destroy; begin FHaltEvent.Free; inherited; end; procedure TmyThread.execute; begin while not terminated do begin //do something SuspendIfHalted; end; end; procedure TmyThread.Halt; begin FHaltEvent.ResetEvent; end; function TmyThread.Halted: boolean; begin result:= FHaltEvent.WaitFor(0) <> wrsignaled; end; procedure TmyThread.SuspendIfHalted; begin FHaltEvent.WaitFor(infinite); end; procedure TmyThread.Terminate; begin if Halted then FHaltEvent.SetEvent; inherited; end; |
AW: W1000 Symbol 'Resume' ist veraltet ????
![]() Zitat:
Die optionale Verwendung von Events oder Sleep hatte ich ja bereits genannt, siehe auch ![]() Wie auch in der Delphi-Hilfe werden in jedem MSDN-Artikel leider nur Teilaspekte angesprochen. Grüsse, Dirk |
AW: W1000 Symbol 'Resume' ist veraltet ????
So habe mich jetzt mal entgültig für Tryer Vorschlag entschieden.
Es scheint alles so zu funktionieren wie vorher. Destotrotz muss ich nochmal nerven. Ich verwende jetzt
Delphi-Quellcode:
if not VisDataThread.Suspended then
VisDataThread.Halt; anstelle von
Delphi-Quellcode:
VisDataThread.Suspend;
Delphi-Quellcode:
Continue anstelle von Resume.
procedure TVisDataThread.ResumeVis;
var p1: PDWORD; begin WaitCounter := 0; p1 := FShareMemPointer; Inc(p1, 70); p1^ := 0; if Suspended then Continue; end; 1 Frage ist "Halt" nicht etwas ungünstig von der namensgebung gewählt? Eigentlich beendet der Befehlt Halt ja die ganze Anwendung .. (OK hier als Privat deklariert) Es geht mir aber um die Namensgebung ;)
Delphi-Quellcode:
Wenn ich den Thread erstelle
procedure TVisDataThread.Execute;
const _SECOND = 10000000; var qwDueTime: Int64; liDueTime: _LARGE_INTEGER; ErrMsg: string; begin if VisTimer = 0 then Exit; // Create a negative 64-bit integer that will be used to // signal the timer 1/4 seconds from now. qwDueTime := -1 * (_SECOND div 4); // Copy the relative time into a LARGE_INTEGER. liDueTime.LowPart := DWORD(qwDueTime and $FFFFFFFF); liDueTime.HighPart := longint(qwDueTime shr 32); if MySetWaitableTimer(VisTimer, // handle to a timer object TLargeInteger(liDueTime), // when timer will become signaled FDelayMS, // periodic timer interval nil, // pointer to the completion routine nil, // data passed to the completion routine False {flag for resume state}) then // Following sentences are repeated every FDelayMS interval all the time from initial // start up to program end. repeat // We need to re-adjust timer interval according to the parameter "DelayMS" of vis plug-in. // (in case we exchange vis plug-ins) if FDelayMSChanged then begin FDelayMSChanged := False; CancelWaitableTimer(VisTimer); MySetWaitableTimer(VisTimer, TLargeInteger(liDueTime), FDelayMS, nil, nil, False); end; if WaitForSingleObject(VisTimer, 1000 {1sec}) = WAIT_OBJECT_0 then begin DoOnVisTimer; end else Terminate; SuspendIfHalted; // Added until Terminated else begin ErrMsg := SysErrorMessage(GetLastError); ShowErrorMsgBox(ErrMsg); Terminate; end; end;
Delphi-Quellcode:
erstelle ich eine CriticalSection
constructor TVisDataThread.Create(var DataReadyMsg: HWND; var MemPointer: Pointer);
begin inherited Create(True); DriveThreadId := 0; FShareMemPointer := GetBufferAddress; MemPointer := FShareMemPointer; VisTimer := CreateWaitableTimer(nil, False, 'BassVisTimer'); if VisTimer <> 0 then begin DataReadyMsg := FDataReadyMsg; FDelayMS := 0; ModuledelayMs := 0; FDelayMSChanged := False; FThreadReady := True; end; LockFlag := TCriticalSection.Create; end; Die 2 Frage ist nun wo ist der Unterschied zwischen CriticalSection und EntercriticalSection? Nicht das selbe? Wo wäre es dann angebracht wenn nicht das gleiche EntercriticalSection und LeaveCriticalSection in TVisDataThread.Execute unterzubringen? Jetzt nicht schimpfen.. Ja ich muss mich mit dem Thema noch mehr beschäftigen :) War ja bisher nicht nötig da in älteren vers. von Delphi das problem bisher nicht auftrat. gruss |
AW: W1000 Symbol 'Resume' ist veraltet ????
"Halted" ist eine Funktion, die nur testet ob der Thread angehalten wurde (ich habe mich an die Namen von Tryer gehalten).
In der Methode Terminate muss dies ja überprüft werden, ansonsten führt folgendes zum Deadlock, wenn der Thread im Haltezustand ist:
Delphi-Quellcode:
Diese Sache benötigts du bei allen Methoden, wo ein Thread schlafen gelegt wird (auch bei Tyrer)
myThread.Terminate;
myThread.WaitFor; <--- Programm tot myThread.Free; |
AW: W1000 Symbol 'Resume' ist veraltet ????
Danke sirius hab meinen Beitrag nochmal editiert.
Komme mit einigen sachen noch nicht ganz klar gruss |
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
(Suche nach "SuspendThread race condition") Zitat:
|
AW: W1000 Symbol 'Resume' ist veraltet ????
Kann sich nochmal bitte jemand dieser Frage annehmen?
![]() gruss |
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
2. CriticalSection ist ein Handle-Objekt. EnterCriticalSection ist eine Funktion auf dieses Handle-Objekt. TCriticalSection ist eine Klasse, welches das Handle-Objekt CriticalSection kapselt. TCriticalsection.EnterCriticalSection ist eine Methode vorheriger Klasse. Was war eigentlich genau deine Frage? Deine 3. Frage verstehe ich nicht. |
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
Dann habe ich zwar das Handle object erstellt aber keine Function welche das handle verwaltet (bzw. damit arbeitet) Die Frage war .. An welcher stelle ist es sinnvoll EntercriticalSection und LeaveCriticalSection in TVisDataThread.Execute unterzubringen? wo könnte hier etwas Kritisch sein das ich EntercriticalSection verwenden muss, sollte? Muss mal bei MS lesen wofür EntercriticalSection genau steht ;) Verstehe die Anwendung der Function wohl noch nicht! gruss |
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
Welche Variablen in Execute verwendest du auch außerhalb des Threads (und zwar in dem Moment, wo der Thread läuft)? |
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
|
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
FDelayMSChanged wird aufgerufen wenn ein neues Plugin gestartet wird und die ms sich geändert haben. ps.. ist aber vom gleichen Thread
Delphi-Quellcode:
gruss
procedure TVisDataThread.SetDelayMS(delayMs: DWORD);
var tmpDelayMS: DWORD; begin tmpDelayMS := delayMs; if tmpDelayMS < 10 then tmpDelayMS := 10; if tmpDelayMS <> FDelayMS then begin if FDelayMS <> 0 then FDelayMSChanged := True; FDelayMS := tmpDelayMS; end; end; |
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
Dieses Problem tritt auf, wenn TmyThread Suspend aufruft und der MainThread gleichzeitig Resume aufruft, was bei deinem Code durchaus passieren kann. Zitat:
Allerdings hast du hier eine Variable allersimplesten Datentypes. Da reichen die interlocked-Funktionen aus und die synchronisation kann entfallen. |
AW: W1000 Symbol 'Resume' ist veraltet ????
Zitat:
Mir ging es eigentlich darum eventuelle hänger beim umschalten auf andere Plugins zu vermeiden. Dafür scheint dann wohl EnterCriticalSection nicht das richtige zu sein. Hab dann wohl was falsch verstanden.. Danke für deine Hilfe gruss |
AW: W1000 Symbol 'Resume' ist veraltet ????
Ich weis grad nicht, wie speziell ich darauf antworten soll.
Für Threads gibt es keine 0815 Lösung. Es gibt ein paar Möglichkeiten, wie man so etwas gestalten kann (z.B. WorkerThread oder ThreadPool, ...) aber du musst es immer speziell an deine Aufgabe anpassen. Die Verwendung einer Critical Section geht am besten über eine Klasse:
Delphi-Quellcode:
Da hier in jeder Methode das gleiche (von der Elternklasse benutzte) Critical-Section-Objekt benutzt wird, kann nur ein einziger Thread in einer der Methoden (zwischen BeginXXX und EndXXX) sein. Wenn gleichzeitig ein anderer Thread auf den String zugreifen will muss er bei BeginXXX warten bis der andere Thread fertig ist.
//Beispiel aus der aktuellen Version (2.03) von TDosCommand
TSyncString=class(TSimpleRWSync) //TSimpleRWSnyc benutzt intern TCriticalSection private FValue:String; procedure setValue(Value:String); function getValue:String; public function length:Integer; property Value:String read getValue write SetValue; procedure Add(Value:String); procedure Delete(Pos,Count:Integer); end; { TSyncString } procedure TSyncString.Add(Value: String); begin BeginWrite; // =EnterCriticalSection try FValue:=FValue+Value; finally EndWrite; //=LeaveCriticalSection end; end; procedure TSyncString.Delete(Pos, Count: Integer); begin BeginWrite; // =EnterCriticalSection try system.Delete(FValue,Pos,Count); finally EndWrite; //=LeaveCriticalSection end; end; function TSyncString.getValue: String; begin BeginRead; // =EnterCriticalSection try result:=FValue; finally EndRead; //=LeaveCriticalSection end; end; function TSyncString.length: Integer; begin BeginRead; // =EnterCriticalSection try result:=system.length(FValue); finally EndRead; //=LeaveCriticalSection end; end; procedure TSyncString.setValue(Value: String); begin BeginWrite; // =EnterCriticalSection try FValue:=Value; finally EndWrite; //=LeaveCriticalSection end; end; Diese Klasse kann jetzt in jedem Thread benutzt werden und es gibt keine Synchronisationsprobleme. so benutzt man CriticalSections am besten. Aber neben CriticalSections gibt es noch eine ganze Reihe anderer Synchronisationsmöglichkeiten (darüber könnte man ein Buch schreiben, was es womöglich auch schon gibt). Die alle aufzulisten und zu erklären würde den Rahmen hier sprengen. Was du für deine booleanVariable noch wissen solltest sind aber die interlocked-Funktionen. Da hat Windows (eigentlich die Intel-Architektur) eine nette Sache, das für das Ändern eines 32bit Wertes kann man (allerdings an jeder Stelle, wo man den Wert schreibend ändert) interlockedAdd, interlockedExchange,... verwenden. Suche einfach mal nach den Funktionen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:36 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