.NET

28 dez, 2011

Recebendo retornos de threads em C#

Publicidade

Como mostrei no artigo anterior, todo programa desenvolvido em C# possui uma thread principal e podemos desenvolver outras threads para serem executadas em segundo plano. Podemos também chamar Threads passando parâmetros para elas. Além da passagem de dados para a Thread, existem situações em que é necessário retornar informações quando a execução da thread estiver concluída.

Para recuperar dados da thread, devemos criar um método que aceita os resultados de retorno como parâmetro. Em seguida, devemos criar um delegate para esse método. O construtor da classe deve aceitar um delegate que representa o método call-back. Antes que a thread esteja concluída, ela chama o delegate de retorno.

O código a seguir é uma calculadora simples, na qual a operação é executada através de uma thread em segundo plano, e o resultado é retornado para a thread principal, para ser mostrado para o usuário. No interior deste código estão os comentários explicando cada bloco.

// C#
class Program
{
static void Main(string[] args)
{
// Recebendo entradas do usuário
Console.WriteLine();
Console.Write(\"Informe o primeiro valor: \");
double d1 = Convert.ToDouble(Console.ReadLine());

Console.WriteLine();
Console.Write(\"Informe o segundo valor: \");
double d2 = Convert.ToDouble(Console.ReadLine());

Console.WriteLine();
Console.WriteLine(\"OPERAÇÕES\");
Console.WriteLine(\"1 - Soma\");
Console.WriteLine(\"2 - Subtração\");
Console.WriteLine(\"3 - Multiplicação\");
Console.WriteLine(\"4 - Divisão\");
Console.Write(\"Informe a operação desejada: \");
Operacao op =
(Operacao)Convert.ToInt32(Console.ReadLine());

// Instância da classe Calculadora
Calculadora calc = new
Calculadora(d1, d2, op,
new ResultDelegate(ResultCallback));

// Criando a thread
System.Threading.ThreadStart ts = new
System.Threading.ThreadStart(calc.Calcular);
System.Threading.Thread t = new
System.Threading.Thread(ts);

// Iniciando a execução da thread
t.Start();

Console.WriteLine();
Console.WriteLine(\"Thread principal em execução.\");
t.Join();
Console.WriteLine();
Console.WriteLine(\"Processamento concluído.\");
Console.ReadKey();
}

// Método executado pelo delegate
public static void ResultCallback(double valor)
{
Console.WriteLine(\"Valor Retornado da Calculadora: {0}\",
valor);
}
}

public class Calculadora
{
// Valores utilizados durante o cálculo.
private double valor1;
private double valor2;
private Operacao operacao;

// Delegate usado para executar o método de
// call-back quando a thread estiver completa
private ResultDelegate callback;

// O construtor obtendo os parâmetros
public Calculadora(double _valor1,
double _valor2,
Operacao _operacao,
ResultDelegate _callback)
{
this.valor1 = _valor1;
this.valor2 = _valor2;
this.operacao = _operacao;
callback = _callback;
}

public void Calcular()
{
double valorResultado;

if (this.operacao == Operacao.Soma)
valorResultado = this.valor1 + this.valor2;
else if (this.operacao == Operacao.Subtracao)
valorResultado = this.valor1 - this.valor2;
else if (this.operacao == Operacao.Multiplicacao)
valorResultado = this.valor1 * this.valor2;
else if (this.operacao == Operacao.Divisao)
valorResultado = this.valor1 / this.valor2;
else
valorResultado = 0;

if (callback != null)
callback(valorResultado);
}
}

// Delegate que define a assinatura
// para o método de callback.
public delegate void ResultDelegate(double valor);

// Enumerador de operações
public enum Operacao
{
Soma = 1,
Subtracao = 2,
Multiplicacao = 3,
Divisao = 4
}

O resultado dessa execução deverá ser algo como mostra a imagem abaixo:

\"Resultado

Nota: Fique sempre atento para a ocorrência de deadlocks. Sempre que necessário, utilize locks nos locais onde a concorrência pode ser grande e causar deadlocks. Isso é assunto para um outro artigo, mas, por enquanto, se quiser saber mais sobre isso, veja este link.

Código fonte

Os códigos fontes podem ser baixados aqui.

Referências