Thread-Save Datenverwaltung
-
ISO/IEC 14882:2003, 18.3 Start and Termination, Absatz 8 schrieb:
The function exit()has additional behavior in this International Standard:
— First, objects with static storage duration are destroyed and functions registered by calling atexit are called. Non-local objects with static storage duration are destroyed in the reverse order of the completion of their constructor. (Automatic objects are not destroyed as a result of calling exit().)207) Functions registered with atexit are called in the reverse order of their registration, except that a function is called after any previously registered functions that had already been called at the time it was registered.208) A function registered with atexit before a non-local object obj1 of static storage duration is initialized will not be called until obj1’s destruction has completed. A function registered with atexit after a non-local object obj2 of static storage duration is initialized will be called before obj2’s destruction starts. A local static object obj3 is destroyed at the same time it would be if a function calling the obj3 destructor were registered with atexit at the completion of the obj3 constructor.
— Next, all open C streams (as mediated by the function signatures declared in <cstdio>) with unwritten buffered data are flushed, all open C streams are closed, and all files created by calling tmpfile() are removed.209)
— Finally, control is returned to the host environment. If status is zero or EXIT_SUCCESS, an implementation-defined form of the status successful termination is returned. If status is EXIT_FAILURE, an implementation-defined form of the status unsuccessful termination is returned. Otherwise the status returned is implementation-defined.210)207) Objects with automatic storage duration are all destroyed in a program whose function main() contains no automatic objects
and executes the call to exit(). Control can be transferred directly to such a main() by throwing an exception that is caught in
main().
208) A function is called for every time it is registered.
209) Any C streams associated with cin, cout, etc (27.3) are flushed and closed when static objects are destroyed in the previous
phase. The function tmpfile()is declared in <cstdio>.
210) The macros EXIT_FAILUREand EXIT_SUCCESSare defined in <cstdlib>.Reicht dies als Quelle?

Grüssli
-
Gut, hab das geändert aber leider hilft mir das bei der Geschwindigkeitsoptimierung nicht viel weiter.
-
Für bessere Performance benutze Critical Sections, das sind keine Kernel Objekte.
Simon
-
Habe gerade diesen Beitrag hier gefunden: Link
Da wird ja relativ genau auf CS und Interlock (was immer das auch ist) eingegangen.
Die Frage bleibt, ist es effektiver das ganze irgendwie über Events und einem Daten-Verwaltungs-Thread zu machen oder so wie es jetzt ist.
-
Matyr schrieb:
Die Frage bleibt, ist es effektiver das ganze irgendwie über Events und einem Daten-Verwaltungs-Thread zu machen oder so wie es jetzt ist.
Unterschiedliche Anforderungen bringen unterschiedliche Ergebnisse.
Prinzipiell ist dein Ansatz passend.
Wenn du zB in ThreadSaveData nur primitive Typen hältst ist ein InterlockedExchange() wahrscheinlich das schnellste. Das Stichwort hier wäre CAS (compare and set/swap).
Crtitcal Sections sind nicht über mehrere Prozesse Hinweg benutzbar dafür idR einen Tick schneller als Mutexes.
Die Performance spielt aber nur dann eine Rolle wenn du oft für kurze Zeit lockst. Wenn du selten für lange Zeit lockst ist es komplett egal.
Das mit den Events und Verwaltungsthread verstehe ich nicht. Kannst du erklären was da gemeint ist?
Und: Was ist das Anforderungsprofil?
-
Die Anforderungen sind sehr kurze locks in denen meist nur kleine Datenmengen gelesen oder geschrieben werden. In der Regel >=20Byte.
Ganz selten auch mehr,in etwa 1kb.
Gelockt soll wenn es performance technisch geht etwa 20 - 40mal in der Sekunde werden.Das was ich mit Verwaltungsthread meine ist ein SON (service orientatet network oder so) system.
Daher ein Thread auf den man mit events zugreift und der den anderen Threads bescheid gibt das Daten belegt werden. (Wenn ich das richtig verstanden habe)
Dadurch soll eine höhere Geschwindigkeit gewährleistet sein und vor allem viel Dynamischer.
-
Muss man eigentlich bei Lesezugriff ein Mutex bzw. CS überhaupt setzen?
Oder reicht es wenn nur abgefragt wird ob irgendwo Schreibzugriff ist?
-
wenn du nur liest, ist das ok
wenn du allerdings iwo schreibst und gleichzeitig in nem anderen thread liest, kann es sein, dass du müll liest
-
Deswegen wird beim Schreiben der Mutex gesetzt, in der lese Funktion wird einfach nur geprüft ob er gesetzt wurde, wenn ja wartet er, wenn nicht wird einfach gelesen.
Problem ist vielleicht nur das wenn das lesen länger als ein Takt dauert und dann etwas Anfängt zu schreiben...
-
Matyr schrieb:
Deswegen wird beim Schreiben der Mutex gesetzt, in der lese Funktion wird einfach nur geprüft ob er gesetzt wurde, wenn ja wartet er, wenn nicht wird einfach gelesen.
Problem ist vielleicht nur das wenn das lesen länger als ein Takt dauert und dann etwas Anfängt zu schreiben...
richtig - deshalb schrieb ich ja, dass es schief geht, wenn ein thread gerade schreibt und der andere liest... (bzw schief gehen kann - nicht muss)
-
So habe dass nun mit CriticalSection implemiert,
zusätzlich habe ich eine eigene CS programmiert (naja mit Anleitung von CodeProject) die schneller sein soll.Nun ist die Frage wie ich die Geschwindigkeiten der beiden mal messen bzw. vergleichen kann. Die Zeit zu messen wird denke ich zu ungenau. Effektiv ist wahrscheinlich ein vergleich der Rechenschritte,
nur weiß ich leider nicht wie das effektiv geht.Ist clock(); ein vernünftiger Ansatz?
-
Matyr schrieb:
Ist clock(); ein vernünftiger Ansatz?
Nö, dafür eignet sich eher QueryPerformanceCounter() (siehe MSDN).
-
So meine CS ist fertig und durchgemessen.
Zeit normalle CS: 3400
Zeit meine CS: 2000Kann aber wegen Optimierung des Compilers vielleicht falsch sein.
Initialisieren ist etwas langsamer, schätzungweise 5-10% was aber anhand der anderen Ergebnisse verkraftbar ist.Mfg. Matyr
Folgendes Messverfahren:
QueryPerformanceCounter((LARGE_INTEGER*)&count1); for(int i=0;i<30000;i++) { EnterCriticalSection(&cs); LeaveCriticalSection(&cs); } QueryPerformanceCounter((LARGE_INTEGER*)&count2); cout<<"Enter/Leave CS: "<<(count2-count1)<<endl; Sleep(50); QueryPerformanceCounter((LARGE_INTEGER*)&count1); for(int i=0;i<30000;i++) { myCs.Lock(); myCs.Unlock(); } QueryPerformanceCounter((LARGE_INTEGER*)&count2); cout<<"Enter/Leave MyCS: "<<(count2-count1)<<endl;