2017-05-01 4 views
0

J'ai la fonction suivante appelée updateEntry qui écrit une valeur dans une table de recherche. Je voudrais créer une version multi-thread de cette fonction. Je regardais dans l'opération atomique __sync_bool_compare_and_swap mais je ne suis pas sûr de savoir comment l'appliquer correctement.Fonction atomique sans verrous pour modifier deux emplacements de mémoire indépendants

Est-il théoriquement possible d'implémenter cette fonction de manière atomique sans verrouillage, puisqu'elle modifie deux emplacements de mémoire indépendants entryLookup[id] et entry?

void updateEntry(Entry ** entryLookup, unsigned int id, int val1, short val2){ 
      Entry * entry  = entryLookup[id]; 
      entry->val1  = val1; 
      entry->val2  = val2; 
      entryLookup[id] += sizeof(Entry); 
    } 
+1

Questions: 1) Pouvez-vous vous assurer que chaque thread accède à l'ensemble disjoint 'id'? 2) Pouvez-vous vous assurer que de modifier 'val1' et' val2' n'affectera jamais le résultat de l'opérateur 'entryLookup'' [] '? 3) Pouvez-vous vous assurer que de modifier la valeur de 'entryLookup' n'affectera aucun thread parallèle (par exemple, le nouvel identifiant n'est pas accessible par un autre thread)? Si l'une de ces règles ne correspond pas, je vois des difficultés à implémenter une concurrence sans verrou. –

+0

@AdrianMaire Merci beaucoup pour votre réponse. J'ai construit une solution qui utilise des ensembles d'identifiants disjoints, mais produire ces ensembles disjoints est coûteux. Je voudrais éviter d'utiliser des ensembles d'identifiants disjoints. Que voulez-vous dire par le point 2.)? –

+1

Q4 - les mises à jour sont-elles effectuées en accord avec les recherches? Sinon, vous pouvez d'abord mettre atomiquement 'entryLookup [id]' à jour, en vous assurant qu'aucun autre thread n'utilisera cette même entrée, puis mettre à jour les valeurs à votre gré (en quelque sorte). Si des recherches ont également lieu, vous devez mettre à jour les deux emplacements séparés, ce qui ne peut pas être fait en utilisant des opérations atomiques primitives. – eran

Répondre

1

Pour rendre ce thread-safe, vous pouvez augmenter entryLookup[id] pour vous assurer que tout autre thread qui vient plus tard ne peut pas changer la même entrée, puis remplissez les valeurs. Une addition atomique est nécessaire lorsque l'ancienne valeur est renvoyée:

void updateEntry(Entry ** entryLookup, unsigned int id, int val1, short val2) 
{ 
    Entry * entry = __sync_fetch_and_add(&entryLookup[id], sizeof(Entry)); 
    entry->val1 = val1; 
    entry->val2 = val2; 
} 
+0

Je viens de noter que @eran a déjà donné cette réponse dans les commentaires. – peppincsoda

+0

C'est simple et devrait résoudre mon problème. Merci beaucoup pour cette excellente réponse. –

+0

@peppincsoda Le problème ici est que la modification des deux entrées 'val' n'est jamais libérée (synchronisée). Comment pouvez-vous accéder en toute sécurité 'entry' dans un autre thread? – LWimsey