![]() |
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Zitat:
Delphi-Quellcode:
ist tatsächlich nicht zwingend erforderlich, sondern nur eine Performance-Optimierung (
const
Delphi-Quellcode:
und
const
Delphi-Quellcode:
werden intern [meistens] als Pointer umgesetzt, wie a.def korrekterweise angemerkt hat). Im Falle von String bewirkt es vor allem, dass die automatische Referenzzählung deaktiviert und grade KEINE lokale Kopie erzeugt wird.
var
|
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Zitat:
|
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Zitat:
![]() Zitat:
Delphi-Quellcode:
weniger um den RefCounter ansich, sondern unnötige lokale Kopien und Speicheroperationen. Wenn man sich mal anschaut, wie eine leere Funktion mit String Parameter ohne
const S: String
Delphi-Quellcode:
oder
const
Delphi-Quellcode:
aussieht:
var
Code:
Im Vergleich zu einer Funktion mit
00822538 55 push ebp
00822539 8BEC mov ebp,esp 0082253B 51 push ecx 0082253C 8945FC mov [ebp-$04],eax 0082253F 8B45FC mov eax,[ebp-$04] 00822542 E82D79BEFF call @UStrAddRef 00822547 33C0 xor eax,eax 00822549 55 push ebp 0082254A 686B258200 push $0082256b 0082254F 64FF30 push dword ptr fs:[eax] 00822552 648920 mov fs:[eax],esp 00822555 33C0 xor eax,eax 00822557 5A pop edx 00822558 59 pop ecx 00822559 59 pop ecx 0082255A 648910 mov fs:[eax],edx 0082255D 6872258200 push $00822572 00822562 8D45FC lea eax,[ebp-$04] 00822565 E82678BEFF call @UStrClr 0082256A C3 ret 0082256B E9C86DBEFF jmp @HandleFinally 00822570 EBF0 jmp $00822562 00822572 59 pop ecx 00822573 5D pop ebp 00822574 C3 ret
Delphi-Quellcode:
bzw.
const
Delphi-Quellcode:
String-Parameter:
var
Code:
Hier sieht man ganz gut, dass man durch diese kleine Optimierung doch deutlich Overhead einspart.
00822578 55 push ebp
00822579 8BEC mov ebp,esp 0082257B 51 push ecx 0082257C 8945FC mov [ebp-$04],eax 0082257F 59 pop ecx 00822580 5D pop ebp 00822581 C3 ret |
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Dass der Compiler so etwas nicht automatisch optimiert war mir immer schon ein Rätsel...
|
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Zuerst möchte ich mich für die vielen hilfreichen Beiträge bedanken, habe wieder etwas dazu gelernt. Bevor ich nun die vielen nützlichen Vorschläge umsätze, möchte ich gerne zu meiner eigentlichen Frage zurückkehren: wäre mein geposteter Code so in Ordnung oder sollen die Zugriffe auf den Queue-Thread zusätzlich mit einer TCriticalSection abgesichert werden?
|
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Wenn ein anderer Thread TapDataReceiverQueue.AddToQueue aufruft musst Du natürlich im Thread
das:
Delphi-Quellcode:
absichern. Allerdings ACHTUNG bei Deinem eigenartigen Konstrukt. Da DeleteFromQueue() eine Prozedur von TapDataReceiverQueue ist UND Du dort schon die CriticalSection benutzt darfst Du diese nicht noch mal absichern. Ansonsten kann ein DEADLOCK entstehen. Also besser alle Methoden in TapDataReceiverQueue integrieren und mit Criticalsection absichern. Dann nie direkt auf die Liste gehen. So kannn nichts passieren.
try
if Assigned(FQueue.Items[0]) then try QueueItem := TapDataReceiverQueueItem(FQueue.Items[0]); TapDataReceiver.Create(false, QueueItem.ClientData, QueueItem.Target, QueueItem.Priority); finally DeleteFromQueue(0); end; Ergänzung: Das TapDataReceiverQueue.Count natürlich auch. |
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Zitat:
Delphi-Quellcode:
wird nur aus dem vom Thread selbst aufgerufen. Public sind nur
DeleteFromQueue()
Delphi-Quellcode:
und
AddToQueue()
Delphi-Quellcode:
. In beiden sind die Zugriffe auf die TObjectList geschützt (für Count nachträglich). Andere Methoden gibt es nicht. Was ist gemeint mit "alle Methoden in TapDataReceiverQueue integrieren und mit Criticalsection absichern"?
Count()
|
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Delphi-Quellcode:
Das bedeutet Du mischst Zugriffe auf die Lokale Liste der Klasse (ohne Absicherung) mit Methoden der Klasse (inkl. Absicherung).
try
if Assigned(FQueue.Items[0]) then // --> hier ist ein direkter Zugriff auf die "interne" Liste ohne Absicherung try QueueItem := TapDataReceiverQueueItem(FQueue.Items[0]); // hier ebenfalls TapDataReceiver.Create(false, QueueItem.ClientData, QueueItem.Target, QueueItem.Priority); // was ist eigentlich das hier? finally DeleteFromQueue(0); // hier ist der Zugriff über eine Methode der Klasse mit Absicherung end; Meiner Meinung nach solltest Du die Klasse
Delphi-Quellcode:
so bauen dass Du aus dem Thread alles mit Klassenmethoden machen kannst (besser MUSST). Zum Beispiel eine Methode Pop um die Objekte zu holen. In der Klasse sicherst Du alles mit der CriticalSection ab. Somit muss sich kein Aufrufer der Methoden um etwas kümmern. Egal aus welchem Thread. Dafür würde sich übrigens die Generische TQueue ev. besser eignen als die TObjectlist.
TapDataReceiverQueue
|
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Hmm..
Also: Generell MUSS jeder Zugriff von verschiedenen Threads auf Variablen gekapselt werden. Dabei ist es egal ob auf die Variable von externen Threads oder vom eigenen Thread darauf zugegriffen wird. Es sind alle konkurierende Threads. Somit müssen 'Add' 'Count' 'Delete' 'Extract' 'READ' und alle eventuell weiteren Zugriffe auf deine Liste gekapselt werden! |
AW: Zugriffe auf Objekt aus mehreren Threads - wie richrig synchronisieren?
Heißt kapseln, dass CriticalSection Enter und Leave bzw TThread.Queue() reicht?
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:59 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