Componentes de thread-Safe.

O compartilhamento de recursos entre threads é uma necessidade freqüente em programação multithread. Vários threads talvez precise acessar um banco de dados compartilhado, por exemplo, ou fazer atualizações em um conjunto de variáveis do sistema. Quando mais de um segmento compete simultaneamente para acesso a recursos compartilhados, a possibilidade de um condição de corrida ocorre. Uma condição de corrida existe quando um thread modifica um recurso em um estado inválido e, em seguida, outro thread tenta acessar o recurso e usá-lo no estado inválido. Considere o exemplo a seguir:

Public Class WidgetManipulator
Public TotalWidgets as Integer = 0
Public Sub AddWidget()
   TotalWidgets += 1
   Console.WriteLine("Total widgets = " & TotalWidgets.ToString)
End Sub
Public Sub RemoveWidgets()
   TotalWidgets -= 10
End Sub
End Class
public class WidgetManipulator
{
   public int TotalWidgets = 0;
   public void AddWidget()
   {
      TotalWidgets++;
      Console.WriteLine("Total widgets = " + TotalWidgets.ToString());
   }
   public void RemoveWidgets()
   {
      TotalWidgets -= 10;
   }
}

Essa classe expõe dois métodos. Um método, AddWidget, adiciona 1 para o TotalWidgets de campo e grava o valor para o console. O segundo método subtrai 10 do valor de TotalWidgets. Considere o que poderia acontecer se dois threads simultaneamente tentou acessar a mesma instância da WidgetManipulator classe. Um segmento pode chamar AddWidget ao mesmo tempo em que o segundo segmento chamado RemoveWidgets. Nesse caso, o valor de TotalWidgets poderia ser alterado pelo segundo thread antes que um valor exato que poderia ser relatado pelo thread primeiro. Essa condição de corrida pode causar resultados imprecisos sejam relatados e pode causar corrupção de dados.

Evitando condições de corrida usando bloqueios

Você pode proteger seções críticas do seu código de condições de corrida, empregando bloqueios. Um bloqueio, representado pela palavra-chave de Visual Basic Instrução SyncLock, ou a palavra-chave C# instrução de bloqueio, permite que um único thread de execução para obter direitos de execução exclusivo em um objeto. O exemplo a seguir demonstra os bloqueios:

SyncLock MyObject
' Insert code that affects MyObject.
End SyncLock
lock(MyObject)
{
   // Insert code that affects MyObject.
}

Quando um bloqueio é encontrado, a execução no objeto especificado (MyObject no exemplo anterior) é bloqueado até que o thread pode obter acesso exclusivo para o objeto. Quando o fim do bloqueio é alcançado, o bloqueio seja liberado e a execução continua normalmente. Você só pode obter um bloqueio em um objeto que retorna uma referência. Um tipo de valor não pode ser bloqueado dessa maneira.

Desvantagens de bloqueios

Embora o uso de bloqueios garante que vários threads acessem simultaneamente um objeto, eles podem causar degradação de desempenho significativos. Imagine um programa com muitos segmentos diferentes em execução. Se cada thread precisa usar um determinado objeto e tem de esperar para obter um bloqueio exclusivo no objeto antes de executar, os segmentos serão todos cessar a execução e faça backup atrás de outro, reduzindo o desempenho. Por esses motivos, você só deve usar bloqueios quando houver um código que deve ser executado como uma unidade. Por exemplo, você pode atualizar vários recursos que estavam interdependentes. Esse código é considerado atômica. Restringir seus bloqueios apenas ao código que deve ser executado atomicamente permitirá escrever componentes multithread que garantem a segurança de seus dados e ainda manter um bom desempenho.

Você também deve ter cuidado para evitar situações onde deadlocks podem ocorrer. Nesse caso, vários threads esperam uns aos outros para liberar os recursos compartilhados. Por exemplo, o Thread 1 talvez segure um bloqueio no recurso a e está aguardando o recurso b. O thread 2, por outro lado, pode ter um bloqueio no recurso b e aguarda o recurso a. Nesse caso, nenhum thread será permitido para continuar. A única maneira de evitar situações de deadlock é cuidadoso através de programação.

Consulte também

Tarefas

Como: Coordenar vários Threads de execução

Como: Manipular controles de Threads

Demonstra Passo a passo: Criação de um componente Multithreaded simples com Visual Basic

Demonstra Passo a passo: Criação de um componente Multithreaded simples com Visual C#

Referência

BackgroundWorker

Conceitos

Event-based Asynchronous Pattern Overview

Outros recursos

Multithreading em componentes