2017-10-19 7 views
0

Je lis C++ Concurrency in Action, et viennent à travers les énoncés suivants qui décrivent deadlock (page 47 ~ 48):Comment comprendre les instances de la même classe provoquent un problème d'interblocage dans C++ Concurrency in Action?

Le conseil commun pour éviter l'impasse est de toujours verrouiller les deux mutex dans le même ordre: si vous avez toujours verrouille mutex A avant mutex B, alors vous ne serez jamais bloqué. Parfois, cela est simple, parce que les mutex servent à des fins différentes, mais d'autres fois ce n'est pas si simple, comme lorsque les mutex protègent chacun une instance distincte de la même classe. Considérons, par exemple, une opération qui échange des données entre deux instances de la même classe; afin de garantir que les données sont correctement échangées, sans être affectées par des modifications simultanées, les mutex sur les deux instances doivent être verrouillés. Cependant, si un ordre fixe est choisi (par exemple, le mutex pour l'instance fournie en tant que premier paramètre, puis le mutex pour l'instance fournie en tant que deuxième paramètre), cela peut se retourner contre: il suffit de deux threads pour essayer échanger des données entre les deux mêmes instances avec les paramètres échangés, et vous avez un blocage!

Je suis très confus au sujet de la signification de la partie suivante:

Toutefois, si un ordre fixe est choisi (par exemple, le mutex pour l'instance fourni comme premier paramètre, le mutex pour l'instance fournie en tant que deuxième paramètre), cela peut se retourner contre: tout ce qu'il faut, c'est que deux threads essaient d'échanger des données entre les deux mêmes instances avec les paramètres échangés, et vous avez un blocage!

Dans les versions précédentes, il se réfère "an operation", il mentionne "two threads to try to exchange data". Quel est le scénario que l'auteur veut exprimer?

Répondre

1

Cela fait référence à une situation comme celle-ci:

Vous avez une fonction

void foo(bar& a, bar& b) { 
    lock_guard<mutex> lock1(a.mutex); 
    ... 
    lock_guard<mutex> lock2(b.mutex); 
} 

qui, à première vue, semble suivre les conseils de toujours verrouiller les mutex dans le même ordre.

Mais si vous avez

bar a, b; 

foo pourrait être appelé comme

foo(a, b); 

dans un thread, et comme

foo(b, a); 

dans un autre. Ensuite, vous avez une impasse.

0

L'opération d'échange est commutative, vous n'avez donc aucune garantie que les algorithmes effectueront cette opération avec le même ordre d'arguments. Donc, s'il y a l'objet a et b, un thread peut faire Swap(a, b) et l'autre Swap(b, a) et les verrous de résultat final sont acquiescés dans un ordre différent.

Si la temporisation est mauvaise, cela conduira à un verrouillage mort. Notez que cela peut être encore plus contraignant trois objets et trois threads faire: Swap(a, b), Swap(b, c), Swap(c, a). Ici le premier argument de verrouillage que le second argument peut aussi conduire à un verrou mort.

1

Dans les versions précédentes, il se réfère « une opération », il mentionne « deux fils pour essayer d'échanger des données »

Vous avez manqué la fin de la phrase! Il dit "deux threads pour essayer d'échanger des données entre les deux mêmes instances". Il ne s'agit pas d'échanger des données entre les threads, il s'agit d'un thread échangeant des données entre deux instances d'un type, et un autre thread échangeant des données entre les deux mêmes instances.