Service Pack do Visual Studio 2010

Deixe um comentário

A versão final do Service Pack 1 do Visual Studio 2010 está disponível para download.

Este service pack resolve problemas que foram encontrados através de uma combinação de clientes e de parceiros Microsoft, bem como testes internos. Este pacote oferece aos usuários do Visual Studio melhorias na estabilidade, agilidade e desempenho. O feedback recebido durante o lançamento da versão beta será utilizado para entregar uma versão final do service pack.

Fonte: Microsoft

A descrição completa das funcionalidades disponíveis neste service pack, bem como os problemas resolvidos, podem ser encontrados neste artigo.

Para fazer o download do Service Pack 1 do Visual Studio 2010, acesse este link.
Anúncios

Sincronização de Threads em C# e VB.NET

1 Comentário

Aviso: Boa parte do conteúdo deste artigo é uma tradução de artigo “Thread Synchronization (C# and Visual Basic)” disponibilizado pela Microsoft, que pode ser encontrado aqui.

Um dos benefícios do uso de múltiplas threads em uma aplicação é que cada uma delas é executado de forma assíncrona. Em aplicações desktop, isto permite que tarefas que consomem muito tempo possam ser executadas em segundo plano enquanto a janela do aplicativo e os controles continuam respondendo. Para aplicações em servidores, múltiplas tarefas fornecem a capacidade de lidar com cada solicitação de entrada com uma thread diferente, caso contrário, cada novo pedido não será atendido até que o pedido anterior tenha completado.

No entanto, a natureza assíncrona de threads significa que o acesso a recursos compartilhados, como arquivos, conexões de rede e memória devem ser sincronizados. Caso contrário, duas ou mais threads podem acessar o mesmo recurso ao mesmo tempo, e cada um desconhece a atuação da outra ação e o resultado é a corrupção de dados imprevisível e possíveis deadlocks.

Há algum tempo, fiz outros artigos que demonstram o uso de threads em C# e Visual Basic. Você pode encontrá-los aqui:

Lock e SyncLock

O Lock (C#) e o SyncLock (VB.NET) são declarações que podem ser utilizadas para garantir que um bloco de código seja executado até sua conclusão, prevenindo a interrupção da execução por outras threads. Essas declarações são interpretadas pelo compilador como bloqueios para um determinado objeto em um bloco de códigos. Se outra thread tenta executar o código envolvido pelo lock / SyncLock, ela esperará até que a primeira thread termine a execução e libere o objeto / código bloqueado.

//C#
public class LockTest
{
    public void TestarLock()
    {
        lock (this)
        {
            // Código que estará protegido pelo lock.
        }
    }
}
'VB.NET
Public Class LockTest
    Public Sub TestarLock()
        SyncLock Me
            ' Código que estará protegido pelo lock.
        End SyncLock
    End Sub
End Class

Sincronização de Eventos e Wait Handles

Existem dois tipos de sincronização: AutoResetEvent e ManualResetEvent. Eles diferem apenas na medida em que as mudanças são setadas automaticamento no AutoResetEvent e manualmente no ManualResetEvent. O ManualResetEvent permite que qualquer número de threads possa ser alinhado e ter seu estado atualizado.

Métodos são usados para esperar a execução de um ou mais threads. Esses métodos indicam ao compilador quando e quantas threads devem ter o processamento concluído para que o fluxo continue. São eles: WaitOne, WaitAny e WaitAll. WaitOne faz com que o compilador espere a execução de um único thread estar concluída. WaitAny faz o compilador aguardar a execução dos métodos indicados. WaitAll bloqueia a execução até que todas as threads estejam concluídas. Para sinalizar a conclusão da execução de uma thread usa-se o método Set.

// C#
namespace GerenciaSincronizacao
{
    public class GerenciarThreads
    {
        private ManualResetEvent[] manualResetEvent;

        private void ExecutarThread0(object obj)
        {
            Thread.Sleep(20000);
            Console.WriteLine("Thread 0 concluída!");
            manualResetEvent[0].Set();
        }

        private void ExecutarThread1(object obj)
        {
            Thread.Sleep(13000);
            Console.WriteLine("Thread 1 concluída!");
            manualResetEvent[1].Set();
        }

        private void ExecutarThread2(object obj)
        {
            Thread.Sleep(9000);
            Console.WriteLine("Thread 2 concluída!");
            manualResetEvent[2].Set();
        }

        private void ExecutarThread3(object obj)
        {
            Thread.Sleep(17000);
            Console.WriteLine("Thread 3 concluída!");
            manualResetEvent[3].Set();
        }

        public void Executar()
        {
            manualResetEvent = new ManualResetEvent[4];

            manualResetEvent[0] = new ManualResetEvent(false);
            ThreadPool.QueueUserWorkItem(this.ExecutarThread0);

            manualResetEvent[1] = new ManualResetEvent(false);
            ThreadPool.QueueUserWorkItem(this.ExecutarThread1);

            manualResetEvent[2] = new ManualResetEvent(false);
            ThreadPool.QueueUserWorkItem(this.ExecutarThread2);

            manualResetEvent[3] = new ManualResetEvent(false);
            ThreadPool.QueueUserWorkItem(this.ExecutarThread3);

            WaitHandle.WaitAll(manualResetEvent);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            GerenciarThreads gt = new GerenciarThreads();
            gt.Executar();

            Console.WriteLine("Pressione ENTER para terminar.");
            Console.ReadKey();
        }
    }
}
' VB.NET
Namespace GerenciaSincronizacao
    Public Class GerenciarThreads
        Private manualResetEvent As ManualResetEvent()

        Private Sub ExecutarThread0(obj As Object)
            Thread.Sleep(20000)
            Console.WriteLine("Thread 0 concluída!")
            manualResetEvent(0).[Set]()
        End Sub

        Private Sub ExecutarThread1(obj As Object)
            Thread.Sleep(13000)
            Console.WriteLine("Thread 1 concluída!")
            manualResetEvent(1).[Set]()
        End Sub

        Private Sub ExecutarThread2(obj As Object)
            Thread.Sleep(9000)
            Console.WriteLine("Thread 2 concluída!")
            manualResetEvent(2).[Set]()
        End Sub

        Private Sub ExecutarThread3(obj As Object)
            Thread.Sleep(17000)
            Console.WriteLine("Thread 3 concluída!")
            manualResetEvent(3).[Set]()
        End Sub

        Public Sub Executar()
            manualResetEvent = New ManualResetEvent(3) {}

            manualResetEvent(0) = New ManualResetEvent(False)
            ThreadPool.QueueUserWorkItem(AddressOf Me.ExecutarThread0)

            manualResetEvent(1) = New ManualResetEvent(False)
            ThreadPool.QueueUserWorkItem(AddressOf Me.ExecutarThread1)

            manualResetEvent(2) = New ManualResetEvent(False)
            ThreadPool.QueueUserWorkItem(AddressOf Me.ExecutarThread2)

            manualResetEvent(3) = New ManualResetEvent(False)
            ThreadPool.QueueUserWorkItem(AddressOf Me.ExecutarThread3)

            WaitHandle.WaitAll(manualResetEvent)
        End Sub
    End Class

    Class Program
        Private Shared Sub Main(args As String())
            Dim gt As New GerenciarThreads()
            gt.Executar()

            Console.WriteLine("Pressione ENTER para terminar.")
            Console.ReadKey()
        End Sub
    End Class
End Namespace

A classe Interlocked

Você pode usar os métodos da classe Interlocked para evitar problemas que podem ocorrer quando várias threads tentam simultaneamente atualizar ou comparar um mesmo valor. Os métodos dessa classe permitem que você assegure o incremento, decremento, troca e comparação entre valores em qualquer thread.

As operações mais utilizadas desta classe são:

  • O método Add adiciona um valor inteiro para uma variável e retorna o novo valor da variável.
  • O método Read lê um valor inteiro de 64 bits.
  • Os métodos Increment e Decrement são utilizados para incrementar ou decrementar valores em uma variável e retornam o valor resultante.

O código a seguir demonstra o uso do Increment.

// C#
private static ManualResetEvent[] manualResetEvents;

public void Teste()
{
    int intQuantidadeInteracoes = 10;
    int intContador = 0;

    manualResetEvents = new ManualResetEvent[intQuantidadeInteracoes];

    for (int i = 0; i < intQuantidadeInteracoes; i++)
    {
        manualResetEvents[intContador] = new ManualResetEvent(false);

        ThreadPool.QueueUserWorkItem(this.Executar, intContador);

        Interlocked.Increment(ref intContador);
    }

    WaitHandle.WaitAll(manualResetEvents);
}

public void Executar(object intContador)
{
    Console.WriteLine("Posição atual do contador: {0}",
        Convert.ToInt32(intContador));

    manualResetEvents[Convert.ToInt32(intContador)].Set();
}
' VB.NET
Private Shared manualResetEvents As ManualResetEvent()

Public Sub Teste()
    Dim intQuantidadeInteracoes As Integer = 10
    Dim intContador As Integer = 0

    manualResetEvents = New ManualResetEvent(intQuantidadeInteracoes - 1) {}

    For i As Integer = 0 To intQuantidadeInteracoes - 1
        manualResetEvents(intContador) = New ManualResetEvent(False)

        ThreadPool.QueueUserWorkItem(AddressOf Me.Executar, intContador)

        Interlocked.Increment(intContador)
    Next

    WaitHandle.WaitAll(manualResetEvents)
End Sub

Public Sub Executar(intContador As Object)
    Console.WriteLine("Posição atual do contador: {0}", Convert.ToInt32(intContador))

    manualResetEvents(Convert.ToInt32(intContador)).[Set]()
End Sub

Referências