Parallelzugriff auf primitive Datentypen
-
Eine einfache Zuweisung könnte tatsächlich atomar sein, bei den kombinierten Operationen (z.B. a=a+10;) ist das nicht mehr gegeben (das dürfte effektiv zerlegt werden in "lade a, addiere 10, speichere a").
Allerdings hängt es vom Prozessor ab, welche Datentypen so primitiv sind, daß sie atomar gelesen/geschrieben werden können (auf einem 8-Bit-Rechner dürfte int nicht als primitv durchgehen) - und zur Not bist du auf der sicheren Seite, wenn du die Daten trotzdem schützt.
-
Tobias W schrieb:
Ihr seid euch also sicher, dass ein Zugriff (zum Beispiel) per = Operator auf einen primitiven Datentyp atomar ist?
nö, auf einer 32-bit maschine ist ein zugriff auf einen 'long long' sicher nicht atomar.
-
Ich habe gerade etwas interessanten in dem Buch "The ACE Programmer's Guide" von Huston, Johnson & Syyid gefunden:
14.1.3 Atomic Operation Wrapper:
On most machine architectures, changes to basic types are atomic; that is, an increment of an integer variable does not require the use of synchronization primitives. However, on most multiprocessors, this is not true and is dependent on the memory ordering properties of the machine. If the machine memory is strongly ordered, modifications made to memory on one processor are immediately visible to the other processors and so synchronization is not required around global variables; otherwise, it is.
[...]Wie man hier aus dem Zitat rauslesen kann, ist es also sehr Hardwareabhängig (wie hier auch schon vermutet). Denke es ist also sicherer auch hier einen Mutex zu spendieren, falls die Applikation später auch auf anderen Rechnern laufen sollte...
-
Performancemässig schlage ich die Verwendung eines rw-mutexes vor. Da können mehrere gleichzeitig lesen ohne sich zu blockieren, aber wenn einer schreiben will, bekommt er den Zugriff alleine.
-
Der Aussage von kingruedi, dass weder Schreib- und Lesezugriffe auf primitive Datentypen atomar ist, kann ich bestätigen.
Aber was passiert wirklich? Liefert der lesende Zugriff auf nicht gesichtert primitive Datentypen undefinierten Müll zurück?
a = a + 12 wird ja prinizpiell so umgeestzt:load a add 12 store a
Entweder hat der lesende Thread also den Wert vor der Zuweisung oder eben den nach der Zuweisung (12) - richtig?
-
Es gibt aus diesem Grund auch atomare Operationen, die durch das OS abgesichert werden.
http://msdn2.microsoft.com/en-us/library/ms684122.aspx
Ist zwar immer noch mehr Overhead als bei einem Single-Statement in Assembler, aber besser als die Verwendung von Locks/Mutexen.
-
Atomare Operationen/Typen sollen im C++0x-Standard Bestandteil der Programmiersprache werden.
Interessant ist vielleicht auch ein Blick in die include/asm-ARCH/atomic.h des Linux-Kernels.
@headhunter
ganz zu schweigen davon, dass moderne CPUs ohnehin den Speicherzugriff nicht synchronisiert/geordnet ablaufen lassen. Das was Tobias W. auch zitiert hat.
-
Danke für die vielen Antworten, habe mich auf jeden Fall entschlossen mich nicht drauf zu verlassen. Lieber jetzt ein bisschen mehr Sorgfalt walten lassen, als später auf die Nase zu fallen.
Werde mir auf jeden Fall mal einen Blick in die atomic.h gönnen, da ich unter Linux die Applikation schreibe.
-
Headhunter schrieb:
Entweder hat der lesende Thread also den Wert vor der Zuweisung oder eben den nach der Zuweisung (12) - richtig?
richtig, aber sowas ist oft kein problem wenn nur ein thread schreibt. die variable hat entweder den zustand vor oder nach der änderung, aber nichts anderes. richtig doof wird's erst, wenn zwei oder mehr schreibzugriffe nötig sind und der lesethread auch zwischenstände zu sehen bekommt.
-
Was atomar ist oder nicht hängt von vielen Faktoren ab. Compiler, CPU, Type (int/short/char/double/...).
Was grundsätzlich NIE atomar ist sind read-modify-write Operationen (solange man keine spezielle Funktion dafür verwendet wie InterlockedIncrement o.ä.), Operationen mit mehreren Variablen etc.
Was auch oft ein Problem ist: die Reihenfolge in der atomare Schreibzugriffe für andere Threads sichtbar werden ist bei vielen CPU nicht garantiert die selbe in der sie "abgesetzt" wurden.
Dann kommt natürlich noch dazu dass der Compiler die Zugriffe "reordern" kann, und dass die CPU die Zugriffe "reordern" kann.
Alles in allem ein schwieriges Thema.