|
A palavra-chave lock marca um bloco de instruções como uma zona crítica ao pegar um mutex para um determinado objeto, executar a instrução e então liberar o bloqueio.
A instrução lock basicamente usa Monitor.Enter e Monitor.Exit, ou seja, Monitor.Enter(this) é executado quando lock(this) é executado, e Monitor.Exit(this) é executado no final da colteada curly. Qual é o seu significado? Para qualquer objeto, a primeira parte da memória é o endereço de todos os métodos, e a segunda parte é um índice. Ele aponta para um SyncBlock na área de cache SyncBlock do CLR. O que isso significa? Ou seja, quando você executa o Monitor.Enter(Object), se o valor do índice do objeto for negativo, selecione um SyncBlock do Cache do SyncBlock e coloque seu endereço no índice do objeto. Isso completa o bloqueio marcado por objeto, e as outras threads querem realizar novamente a operação Monitor.Enter(objeto), o que obterá um índice com um objeto positivo, e então esperar. Até que o índice se torne negativo, ou seja, a thread usa Monitor.Exit(object) para tornar o índice negativo. O que você precisa prestar atenção ao usar a fechadura:
1.lock não pode travar valor nulo Um objeto pode apontar para nulo, mas nulo não precisa ser liberado. (Veja também: Entendendo o Nulo Completo) 2.lock não pode travar o tipo de string, embora também seja um tipo de referência. Porque o tipo de string é "pairado" pelo CLR Isso significa que há apenas uma instância de uma string em todo o programa, e esse mesmo objeto representa esse texto em todas as threads de todos os domínios de aplicação em execução. Portanto, desde que um lock seja colocado em uma string com o mesmo conteúdo em qualquer lugar do processo de aplicação, todas as instâncias dessa string na aplicação serão travadas. Portanto, é melhor trancar membros privados ou protegidos que não serão persistidos. 3.locklock O objeto é a fronteira de memória de um bloco de programa 4. O tipo de valor não pode ser bloqueado, porque o "objeto é liberado" em vermelho no texto anterior, e o tipo de valor não é um tipo de referência 5.lock evita travar tipos públicos ou objetos que não são controlados pelo programa. Por exemplo, se a instância for acessível publicamente, o lock(this) pode ser problemático porque código não controlado também pode travar o objeto. Isso pode levar a deadlocks, onde duas ou mais threads aguardam para liberar o mesmo objeto. Bloquear tipos de dados públicos (em oposição a objetos) também pode causar problemas pelo mesmo motivo. Ao usar lock(this), o valor da variável membro da classe pode ser alterado pelo método que não está na zona crítica
Cenário de aplicação: É frequentemente usado para evitar exceções incertas no valor de variáveis públicas causadas por operações multithreaded, garantindo a segurança das operações
- // statements_lock2.cs
- using System;
- using System.Threading;
- class Account
- {
- private Object thisLock = new Object();
- int balance;
- Random r = new Random();
- public Account(int initial)
- {
- balance = initial;
- }
- int Withdraw(int amount)
- {
- // This condition will never be true unless the lock statement
- // is commented out:
- if (balance < 0)
- {
- throw new Exception("Negative Balance");
- }
- // Comment out the next line to see the effect of leaving out
- // the lock keyword:
- lock(thisLock)
- {
- if (balance >= amount)
- {
- Console.WriteLine("Balance before Withdrawal : " + balance);
- Console.WriteLine("Amount to Withdraw : -" + amount);
- balance = balance - amount;
- Console.WriteLine("Balance after Withdrawal : " + balance);
- return amount;
- }
- else
- {
- return 0; // transaction rejected
- }
- }
- }
- public void DoTransactions()
- {
- for (int i = 0; i < 100; i++)
- {
- Withdraw(r.Next(1, 100));
- }
- }
- }
- class Test
- {
- static void Main()
- {
- Thread[] threads = new Thread[10];
- Account acc = new Account(1000);
- for (int i = 0; i < 10; i++)
- {
- Thread t = new Thread(new ThreadStart(acc.DoTransactions));
- threads[i] = t;
- }
- for (int i = 0; i < 10; i++)
- {
- threads[i].Start();
- }
- }
- }
Copiar código
|