web-dev-qa-db-fra.com

Qu'est-ce qui empêche une condition de course sur une serrure?

Je comprends les bases de quelles courses de données et comment les serrures/mutexes/semi -aphores aident à les empêcher. Mais que se passe-t-il si vous avez une "condition de race" sur la serrure elle-même? Par exemple, deux threads différents, peut-être dans la même application, mais fonctionnant sur différents processeurs, essayez d'acquérir un verrou à la même heure .

Que se passe-t-il alors? Qu'est-ce qui est fait pour éviter cela? Est-ce impossible, ou tout simplement peu probable? Ou est-ce un réel condition de course en attente de se produire?

24
Gavin Howard

Est-ce impossible, ou tout simplement peu probable?

Impossible. Il peut être mis en œuvre de différentes manières, par exemple via le comparer-et-Swap où le matériel garantit une exécution séquentielle. Il peut devenir un peu compliqué en présence de multiples noyaux, voire plusieurs prises et nécessite un compliqué protocole entre les noyaux, mais tout cela est pris en charge.

36
maaartinus

Étudiez le concept d'opérations atomiques "tester et définir".

Essentiellement, l'opération ne peut pas être divisée - il n'est pas possible pour deux choses de le faire exactement au même moment. Il vérifiera une valeur, définissez-la si elle est claire et renvoyez la valeur tel qu'il s'agissait d'un test. Dans une opération de verrouillage, le résultat sera toujours "LOCK == TRUE" après un test et une définition, la seule différence est celle qui est définie ou non au début.

Au niveau du micro-code dans un seul processeur de base, il s'agit d'une instruction indivisible et est facile à mettre en œuvre. Avec plusieurs processeurs multiples et multicœurs, il devient plus difficile, mais comme les programmeurs dont nous n'avions pas besoin de m'inquiéter, car il est conçu pour fonctionner par les gars vraiment intelligents qui font le silicium. Essentiellement, ils font la même chose - faire une instruction atomique qu'une version fantaisie du test et de l'ensemble

17
mattnz

Mettez simplement le code pour entrer dans la section critique est spécialement conçu pour une condition de course ne violera pas l'exclusion mutuelle.

La plupart du temps, les boucles de comparaison atomique sont utilisées qui exécutent au niveau du matériel

while(!CompareAndSet(&lock, false, true));//busy loop won't continue until THIS thread has set the lock to true
//critical section
CompareAndSet(&lock, true, false);

En l'absence de bien étudié Software Solutions pour activer l'exclusion mutuelle.

2
ratchet freak

Il n'est pas possible que deux (ou plus) threads acquièrent une serrure en même temps. Il existe peu de types de méthodes de synchronisation par exemple:

En attente active - Serrure de spin

Pseudocode:

1. while ( xchg(lock, 1) == 1); - entry protocole

XCCHG est un exemple d'opération atomique (existe sur l'architecture x86) qui définit d'abord une nouvelle valeur pour une variable "verrouillage" puis renvoie une valeur ancienne. Atomic signifie qu'il ne peut pas être interrompre - dans d'exemple ci-dessus entre définir une nouvelle valeur et retourner vieux. Résultat déterministe atomique, peu importe quoi.

2. Your code
3. lock = 0; - exit protocol

Lorsque le verrou est égal à 0 Un autre thread peut entrer à la section critique - tandis que la boucle se termine.

Suspension du fil - Par exemple, compter un sémaphore

Il existe deux fonctionnalités atomiques .Wait() et .Signal() _ et nous avons une variable entière permet de l'appeler int currentValue.

Wait():
if (currentValue > 0) currentValue -= 1;
else suspend current thread;

Signal():
If there exists thread suspended by semaphore wake up one of them
Else currentValue += 1;

Maintenant, la résolution du problème de section critique est vraiment facile:

Pseudocode:

mySemaphore.Wait();
do some operations - critical section
mySemaphore.Signal();

Habituellement, votre fil de programmation API devrait vous donner la possibilité de spécifier des threads simultanés simultanés dans la section critique de sémaphore. De toute évidence, il existe plus de types de synchronisation dans des systèmes multithreads (mutex, moniteurs, sémaphore binaires, etc.), mais ils basent sur des idées ci-dessus. On pourrait soutenir que les méthodes qui utilisent la suspension de fil devraient être préférées à l'attente active (la CPU n'est donc pas gaspillée) - Ce n'est pas toujours la vérité. Lorsque le thread est en cours de suspension - une opération coûteuse appelée interrupteur de contexte prend sa place. Cependant, il est raisonnable lorsque le temps d'attente est court (nombre de threads ~ nombre de cœurs).

1
fex