2012-10-31 5 views
4

J'utilise le langage C et Linux comme plate-forme. Je souhaite partager le nombre de structures dans plusieurs processus. Ces structures ont des têtes de listes de liens (ces listes doivent également être partagées) et des pointeurs les uns avec les autres. La mémoire requise pour ces données peut aller jusqu'à 1Mb. Comme je ne peux pas utiliser les pointeurs dans la mémoire partagée, car ils ne seront pas valides pour différents processus.listes de liens multiples dans la mémoire partagée dans Linux

Il y a deux options: 1) soit utiliser les valeurs de décalage au lieu de pointeurs. 2) sinon, utilisez des mémoires partagées différentes et utilisez des ID de mémoire partagée (retournés par shmget) au lieu de pointeurs.

Comme la taille de la mémoire à partager est énorme option qui est mieux? Pouvez-vous suggérer une autre option?

Merci.

+0

Les opérations de marshaling/unmarshaling sont-elles quelque chose que vous pourriez prendre en considération? –

+0

Vous pouvez charger la mémoire partagée à charger à une adresse spécifique (la même adresse dans tous les processus), de sorte que tant que tous les pointeurs sont des données dans la mémoire partagée, ils sont également valables dans tous les processus. Le point clé consiste à s'assurer que le segment de mémoire partagée est chargé à la même adresse dans tous les processus. S'il y a un processus d'ancêtre commun et qu'il charge la mémoire partagée, tout est douceur et lumière; il n'y a pas d'autres problèmes. Si les processus démarrent sans un ancêtre commun, vous devez vous mettre d'accord sur l'adresse et vous assurer que le système vous convient. –

+0

@JonathanLeffler, Comment puis-je m'assurer que les processus commencent par un processus ancêtre commun? – Anand

Répondre

3

utilisation des valeurs de décalage.

au lieu des pointeurs, utilisez size_t décalages (en caractères) depuis le début de la zone de mémoire partagée. Vous devrez le faire partout où vous accédez ou manipulez ces listes.

Edité pour ajouter:

En utilisant les décalages de cette façon compile le code très efficace sur la plupart des architectures, et vous pouvez utiliser les __sync..() Encastrements d'accès et de les modifier atomiquement. Souvenez-vous d'utiliser un intégré pour tous les accès, y compris la lecture: sinon, la valeur peut avoir été modifié atomiquement lors d'une lecture non-atomique (ou vice versa), conduisant à des données corrompues.

Si vous savez que votre mémoire partagée ne dépassera jamais 4 Go, vous pouvez utiliser à la place uint32_t comme type de décalage, en économisant quatre octets par "pointeur" sur les architectures 64 bits. Si vous alignez toutes les cibles sur une limite de 32 bits, vous pouvez quadrupler cela à 8 Go.

L'effet secondaire très agréable d'utiliser uint32_t est que vous pouvez manipuler paires pointeur (deux décalages consécutifs) atomiquement, sur les 64 bits et des architectures 32 bits. En supposant que vous avez également tout dans la mémoire partagée également aligné sur les limites 32 bits, et en utilisant des décalages à chaque unité 32 bits, vous pouvez obtenir AVANCES/paires de pointeur à l'aide atomiquement

static inline void get_pair(void *const base, const uint32_t offset, uint32_t *const pair) 
{ 
    uint64_t *const ptr = (uint64_t *)(offset + (uint32_t *)base); 
    uint64_t  val; 

    val = __sync_or_and_fetch(ptr, (uint64_t)0); 

    memcpy(pair, &val, sizeof val); 
} 

static inline void switch_pair(void *const base, const uint32_t offset, const uint32_t *const new, uint32_t *const old) 
{ 
    uint64_t *const ptr = (uint64_t *)(offset + (uint32_t *)base); 
    uint64_t  oldval, newval; 

    memcpy(newval, &new, sizeof newval); 

    do { 
     /* Note: this access does not need to be atomic, */ 
     memcpy(oldval, ptr, sizeof oldval); 
     /* because the next one verifies it. */ 
    } while (!__sync_bool_compare_and_swap(ptr, oldval, newval)); 

    if (old) 
     memcpy(old, &oldval, sizeof oldval); 
} 

Les travaux __sync...()-ins construits GCC et Intel CC au moins. Le nouveau standard C11 adopte également les built-ins C12 11-style __atomic..(), mais il faudra un certain temps pour que les fonctionnalités soient implémentées dans les compilateurs actuels. Si vous écrivez du code de bibliothèque, ou du code que vous prévoyez de conserver pendant plusieurs années, cela vous fera probablement gagner du temps pour rechercher les deux types prédéfinis et ajouter des commentaires à vous-même (ou à quiconque le conservera) il est temps de faire la transition entre les built-ins), pour décrire le built-in atomique que vous utiliseriez s'ils étaient déjà disponibles.

Enfin, rappelez-vous que l'utilisation de la mémoire partagée comme cela signifie que vous devez observer les mêmes précautions que si vous aviez plusieurs threads accès à la mémoire en même temps. Les opérations atomiques vous aideront, et il y a quelques trucs très intelligents que vous pouvez faire avec des listes si vous pouvez manipuler des paires de pointeurs atomiquement, mais vous devez toujours être très précis sur les cas de coin et les conditions de course possibles.

+0

Merci beaucoup. Cette façon de décalage est utile. – Anand

Questions connexes