2015-05-29 7 views
9

ich eine Struktur haben, die eine atomare Feld enthält:C11 stdatomic und calloc

#include <stdatomic.h> 

struct s { 
    ... 
    atomic_int a; 
}; 

Diese Struktur mit calloc zugeordnet ist:

struct s *p = calloc(1, sizeof(struct s)); 

Ist es tragbar p->a zu erwarten initialisiert werden 0? Es gibt genügend Barrieren im Code, so dass eine schwache konsistente Initialisierung in Ordnung ist, aber ist der Anfangswert garantiert 0?

+0

Falls sich jemand fragt, hat diese Diskussion zu https://github.com/jech/threadpool/commit/63edf80d4605e33254173f1d2b82fbc7da1b249c geführt. – jch

Antwort

3

Nein, das ist im Allgemeinen nicht tragbar. calloc garantiert nur einen byteweisen 0 Wert des zugrunde liegenden Objekts. Für Typen, die einen Zustand haben (können), ist dies nicht gleichbedeutend mit einer Initialisierung. Sie müssen definitiv atomic_init verwenden, um Ihr Objekt in einen gültigen Zustand zu versetzen.

Der Grund dafür sind Plattformen, die zusätzlich zum Basisobjekt eine "Sperre" enthalten, weil sie die entsprechende Assembler-Anweisung nicht implementieren. Um portabel zu sein, müssen Sie wirklich ATOMIC_VAR_INIT oder atomic_init für alle atomaren Objekte verwenden, die nicht statisch zugewiesen sind.

Das gesagt, ich kenne keine vorhandene Plattform, die solche cruft für atomic_int benötigen würde. Wenn Ihre Plattform ATOMIC_INT_LOCK_FREE auf 2 und sizeof(atomic_int)==sizeof(int) eingestellt hat, können Sie relativ sicher sein, dass Ihre Strategie funktioniert. Sie könnten das in einer _Static_assert testen.

+0

Interessant. Der letzte Absatz von Jens bezieht sich auf Abschnitt 7.17.5 der Spezifikation mit der in Abschnitt 7.17.8 impliziten Begründung. – jch

0

Meine Vermutung ist, dass dies nicht tragbar/sicher ist.

Es ist sehr wahrscheinlich, dass calloc() am Ende eine einfache memset() auf dem Speicherbereich tun. Diese einfache memset() würde nicht die erforderlichen Speicherbarrieren ausgeben, um sicherzustellen, dass andere Threads, die die Struktur lesen, die p->a als 0 sehen.

+4

Wie kann ein anderer Thread auf dieses Objekt zugreifen, bevor Calloc zurückkehrt? Nur Calloc kennt seine Adresse. – rici

+0

Entschuldigung, ich war nicht klar - ich weiß, dass die Initialisierung nicht atomar sein wird, ich bin besorgt, ob die Darstellung der atomaren Werte garantiert, dass der Anfangswert 0 sein wird. Ich habe die Frage so bearbeitet, dass sie hoffentlich klarer ist. – jch

+0

@rici Es spielt keine Rolle. 'calloc()' kann zurückgeben und der Zeiger kann an einen anderen Thread übergeben werden. Das garantiert nicht, dass der zweite Thread den Speicher als initialisiert anzeigt. Es könnte immer noch einen vorherigen Müll sehen. – Xaqq

-1
struct s *p = calloc(1, sizeof(struct s)); 
struct s *q = p; 
// some other thread 
foo(*q); 

Die Initialisierung auf Null wird berücksichtigt, bevor p oder eines seiner assginees auf den Speicher zugreifen kann. Es ist 0.

Siehe auch deferred Zero-ing.