Parallelzugriff auf primitive Datentypen
-
Hallo,
ich hab da eine Frage zu Parallelzugriff auf primitive Datentypen (wie int, double, bool, etc...).
Folgender Stand der Dinge: ein Thread greift auf einen primitiven Datentypen lesend und schreibend zu. Ein weiterer nur lesend. Kann ich davon ausgehen, dass der lesende Zugriff so weit atomar ist, dass ich hier keinen Mutex zur Zugriffssteuerung brauche?
Mein Problem ist nämlich, falls ich an dieser Stelle wirklich via Mutex den Datentyp sichern müsste, werde ich in meiner Applikation ein ganzen Haufen Mutexe benötigen. Und dann stellt sich die Frage wie sich das Performancetechnisch auswirken wird (App. läuft auf einem 500MHz PowerPC der schon kräftig ausgelastet ist).
Schonmal vielen Dank für eure Antworten...
PS: falls die Programmiersprache hier ausschlaggebend sein sollte: c++
-
soweit ich weis, sind zugriffe auf primitive datentypen atomar..
-
Viel interessanter ist die Frage, ob die Schreiboperation(en) atomar sind. Wenn Du z. B. in drei Zügen den Wert der Variablen veränderst (siehe Beispiel), dann brauchst Du definitiv einen Mutex.
Beispiel:a = a + 47; ... a = a + b / 11; ... a++;
Wenn Du sowas machst, kann es Dir passieren, daß der Lesezugriff des zweiten Threads zwischen den einzelnen Schreiboperationen auf die Variable zugreift. Jetzt ist die Frage, in wie weit das für das Programm akzeptabel ist....
Edit: Davon ausgehend, daß Du in beiden Threads in einer Schleife immer wieder die Variable veränderst / liest...
-
das ist klar, dann einfach
a = 6; a++; a= a*b; . . . . . temp= a;
temp als gemeinsam gesharte variable
-
Ihr seid euch also sicher, dass ein Zugriff (zum Beispiel) per = Operator auf einen primitiven Datentyp atomar ist?
Ich denke das auch diese Operatoren in mehrere opcode Aufrufe beim Prozessor ankommen, weshalb diese doch auch unterbrochen werden können. Oder irre ich mich?
Wenn sogar Schreiboperatoren atomar wären, hätte ich garkeine Probleme mehr...
Edit:
Was mir gerade so durch den Kopf geschossen ist: spätestens bei 64 Bit Datentypen auf einem 32 Bit Rechner würde ich mir 3 mal überlegen drauf zu vertrauen das es atomare Operationen sind...
-
Die Zugriffe sind weder lesend noch schreibend atomar.
-
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.