Não é possível que dois (ou mais) threads adquiram bloqueio ao mesmo tempo. Existem alguns tipos de métodos de sincronização, por exemplo:
Espera ativa - bloqueio de rotação
Pseudo-código:
1. while ( xchg(lock, 1) == 1); - entry protocole
XCHG é um exemplo de operação atômica (existe na arquitetura x86) que primeiro define novo valor para uma variável "lock" e depois retorna o valor antigo. Atômico significa que não pode ser interrompido - no exemplo acima, entre definir novo valor e retornar antigo. Resultado atômico - determinístico, não importa o quê.
2. Your code
3. lock = 0; - exit protocol
Quando o bloqueio é igual a 0, outro thread pode entrar na seção crítica - enquanto o loop termina.
Suspensão de encadeamento - por exemplo, contagem de semáforo
Existe dois operação atômica .Wait()
e .Signal()
e temos inteiro variável vamos chamá-lo 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;
Agora, resolver o problema crítico da seção é realmente fácil:
Pseudo-código:
mySemaphore.Wait();
do some operations - critical section
mySemaphore.Signal();
Geralmente, a API do encadeamento de programação deve permitir que você especifique o máximo de encadeamentos simultâneos na seção crítica de semáforo. Obviamente, existem mais tipos de sincronização em sistemas multithread (mutex, monitores, semáforo binário etc.), mas eles se baseiam nas idéias acima. Alguém poderia argumentar que os métodos que usam a suspensão de encadeamento devem ser preferidos à espera ativa (para que a CPU não seja desperdiçada) - nem sempre é a verdade. Quando o encadeamento está sendo suspenso, ocorre uma operação cara chamada troca de contexto. No entanto, é razoável quando o tempo de espera é curto (número de threads ~ número de núcleos).