Frage

Bei gemeinsam benutzten Speicher verwendet wird, kann jeder Prozeß den gemeinsamen Bereich in einen anderen Bereich des jeweiligen Adreßraum mmap. Dies bedeutet, dass, wenn Zeiger innerhalb des gemeinsam genutzten Speicherbereich, müssen Sie speichern sie sie als Offsets von Beginn der gemeinsamen Region . Leider verwendet verkompliziert von atomaren Befehlen (zB wenn Sie einen sperrt freien Algorithmus zu schreiben sind versucht, ). Zum Beispiel, sagen Sie eine Reihe von Referenz gezählt Knoten im gemeinsam genutzten Speicher haben, von einem einzigen Schreiber erstellt. Der Schreiber periodisch atomisch aktualisiert einen Zeiger ‚p‘ zu Punkt zu einem gültigen Knoten mit positiven Referenzzählern. Leser wollen ‚p‘ atomar schreiben, weil es an den Anfang eines Knotenpunkte (a struct), deren erstes Element ein Referenzzählwert. Da p auf einen gültigen Knoten zeigt immer, ist die Verweiszähler erhöht wird sicher und macht es sicher zu dereferenzieren ‚p‘ und auf andere Mitglieder. Doch das alles funktioniert nur, wenn alles in demselben Adressraum ist. Wenn die Knoten und die ‚p‘ Zeiger im gemeinsam genutzten Speicher gespeichert sind, dann leiden an den Kunden eine Race-Bedingung:

  1. x = Lese p
  2. y = x + Offset
  3. Increment refcount bei y

Während des Schritts 2 kann p ändern und x kann nicht mehr auf einen gültigen Knoten. Die Problemumgehung nur kann ich mir vorstellen irgendwie alle Prozesse zu zwingen, sich zu einigen, wo die gemeinsam genutzten Speicher auf der Karte, so dass echte Zeiger anstatt Offsets können in der mmap'd Bereich gespeichert werden. Gibt es eine Möglichkeit, das zu tun? Ich sehe in der mmap Dokumentation MAP_FIXED, aber ich weiß nicht, wie ich konnte eine Adresse auswählen, die sicher sein würde.

Edit: Mit Inline-Assembly und der ‚Sperre‘ Präfix auf x86 vielleicht ist es möglich, einen „Zuwachs ptr X mit Y-Offset von Wert Z“ zu bauen? Equivalent-Optionen auf andere Architekturen? Haben nicht viel Assembler geschrieben, weiß nicht, ob die benötigten Anweisungen vorhanden sind.

War es hilfreich?

Lösung

Auf niedrigem Niveau die x86-Atom inctruction tun können alle dieser Baum Schritte auf einmal:

  1. x = Lese p
  2. y = x + Offset Increment
  3. refcount bei y
//
      mov  edi, Destination
      mov  edx, DataOffset
      mov  ecx, NewData
 @Repeat:
      mov  eax, [edi + edx]    //load OldData
//Here you can also increment eax and save to [edi + edx]          
      lock cmpxchg dword ptr [edi + edx], ecx
      jnz  @Repeat
//

Andere Tipps

Dies ist trivial auf einem UNIX-System; benutzen Sie einfach die Shared-Memory-Funktionen:

shgmet, shmat, shmctl, shmdt

void * shmat (int shmid, const void * shmaddr, int shmflg);

  

shmat () legt den gemeinsam genutzten Speicher   Segment nach shmid auf die identifizierten   Adressraum des aufrufenden Prozesses.   Die Befestigung Adresse ist spezifiziert durch   shmaddr mit einem der folgenden   Kriterien:

     

Wenn shmaddr NULL ist, wählt das System   eine geeignete (nicht verwendete) Adresse, bei der   das Segment zu befestigen.

Sie Ihre eigene Adresse angeben hier; z.B. 0x20000000000

Wenn Sie shmget () mit dem gleichen Schlüssel und Größe in jedem Prozess, werden Sie das gleiche Shared-Memory-Segment erhalten. Wenn Sie () an der gleichen Adresse shmat, werden die virtuellen Adressen die gleiche in allen Prozessen sein. Der Kernel kümmert sich nicht darum, was Adressbereich Sie verwenden, solange es nicht Konflikt mit, wo es normalerweise ordnet Dinge. (Wenn Sie die Adresse auslassen, können Sie die allgemeine Region sehen, dass es mag Dinge setzen;. Überprüfen Sie auch Adressen auf dem Stapel und kehrte von malloc () / new [])

Unter Linux, stellen Sie sicher, dass root-Sets SHMMAX in / proc / sys / kernel / shmmax auf eine ausreichend große Anzahl gemeinsam genutzten Speichersegmente aufzunehmen (die Standardeinstellung ist 32 MB).

Wie für atomare Operationen, können Sie sie alle von der Quelle Linux-Kernel erhalten, zum Beispiel

  

include / asm-x86 / atomic_64.h

/*
 * Make sure gcc doesn't try to be clever and move things around
 * on us. We need to use _exactly_ the address the user gave us,
 * not some alias that contains the same information.
 */
typedef struct {
        int counter;
} atomic_t;

/**
 * atomic_read - read atomic variable
 * @v: pointer of type atomic_t
 *
 * Atomically reads the value of @v.
 */
#define atomic_read(v)          ((v)->counter)

/**
 * atomic_set - set atomic variable
 * @v: pointer of type atomic_t
 * @i: required value
 *
 * Atomically sets the value of @v to @i.
 */
#define atomic_set(v, i)                (((v)->counter) = (i))


/**
 * atomic_add - add integer to atomic variable
 * @i: integer value to add
 * @v: pointer of type atomic_t
 *
 * Atomically adds @i to @v.
 */
static inline void atomic_add(int i, atomic_t *v)
{
        asm volatile(LOCK_PREFIX "addl %1,%0"
                     : "=m" (v->counter)
                     : "ir" (i), "m" (v->counter));
}

64-Bit-Version:

typedef struct {
        long counter;
} atomic64_t;

/**
 * atomic64_add - add integer to atomic64 variable
 * @i: integer value to add
 * @v: pointer to type atomic64_t
 *
 * Atomically adds @i to @v.
 */
static inline void atomic64_add(long i, atomic64_t *v)
{
        asm volatile(LOCK_PREFIX "addq %1,%0"
                     : "=m" (v->counter)
                     : "er" (i), "m" (v->counter));
}

Wir Code haben, der auf der Problembeschreibung ähnlich ist. Wir verwenden eine Speicherbild-Datei, Versätze und Dateisperren. Wir haben gefunden, keine Alternative.

Sie sollten keine Angst haben, eine Adresse nach dem Zufallsprinzip zu machen, da der Kernel nur Adressen ablehnt es nicht wie (diejenigen, die im Widerspruch). Siehe meine shmat() Antwort oben, mit 0x20000000000

Mit mmap:

  

void * mmap (void * addr, size_t Länge, int Prot, int flags, int fd, off_t Offset);

     

Wenn Adr nicht NULL, dann wird der Kernel   nimmt es als Hinweis darüber, wo zu   legen die Abbildung; auf Linux, die   Mapping wird auf der nächsten erstellt werden   höhere Seitengrenze. Die Adresse   Die neue Zuordnung wird als die zurück   Ergebnis des Aufrufs.

     

Das Argument flags legt fest, ob   Updates für die Abbildung sind sichtbar   andere Prozesse Abbilden der gleichen   Region und ob Updates   erfolgt durch auf den darunter liegenden   Datei. Dieses Verhalten wird bestimmt durch   einschließlich genau eines der folgenden   Werte in Fahnen:

     

MAP_SHARED diese Zuordnung Teile.   Updates für die Abbildung sind sichtbar   andere Prozesse, die diese Karte   Datei, und an die durch durch   zugrunde liegende Datei. Die Datei kann nicht   tatsächlich bis msync aktualisiert werden (2) oder   munmap () aufgerufen wird.

     

FEHLER

     

EINVAL Wir haben nicht wie Adr, Länge oder   Offset (beispielsweise sind sie zu groß ist, oder   nicht auf einer Seitengrenze ausgerichtet).

Das Hinzufügen der auf den Zeiger versetzen das Potenzial für ein Rennen nicht schaffen, es ist bereits vorhanden. Da zumindest weder ARM noch x86 atomar einen Zeiger lesen kann dann Zugriff auf den Speicher bezieht es sich auf Sie den Mauszeiger Zugriff mit einer Sperre unabhängig von schützen müssen, ob Sie einen Offset hinzufügen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top