O objetivo deste post é fazer com que só exista uma instancia do programa executando por vez.
Como vimos nos posts anteriores podemos "travar" um bloco de codigo para que ele só seja executado por uma thread por vez.
Então que tal bloquear toda a sua aplicação para que ela rode apenas uma por vez??
Como o MSN por exemplo que só roda um cliente na maquina por vez.
É obvio que se você usar o recurso lock não vai dar nenhum pouco certo, pois a nova instancia de seu programa será uma nova thread e ela vai executar normalmente aquele bloco de codigo porque para todos os efeitos o bloco da nova instancia é outro bloco.
Em C# podemos usar a classe Monitor, ao inves do lock como foi explicado no post anterior. A classe Monitor se comporta exatamente como o lock. Se ela se comporta da mesma maneira então não conseguiremos resultados diferentes.
Porém o sistema operacional tem um objeto que pode fazer a mesma coisa.
O nome dele é MUTEX.
Ele é cerca de 33 vezes mais lento do que usar a classe Monitor, porém ele pode bloquear peças de codigo entre diferentes AppDomains.
Descuple a falta de referencia mas esse dado da performance foi tirado do livro CLR via C#, infelizmente não lembro o nome do autor.
Isso é perfeito para o que queremos, pois duas instancias da nossa aplicação são duas appDomains diferentes.
Então vamos deixas as palavras de lado, já que eu não sou muito bom com elas, e começaremos a mostrar o codigo.
//Utilizamos a classe MUTEX
Mutex meuPrograma = null;
try
{
//essa declaração deve ser feita dentro do bloco try,
// pois se nao existir instancia do programa rodando ele vai gerar uma excessão
meuPrograma = Mutex.OpenExisting("PROGRAMA");
}
catch (WaitHandleCannotBeOpenedException) {
Console.WriteLine("Não existe Instancia do programa aberto");
}
if (meuPrograma == null)
{
meuPrograma = new Mutex(true, "PROGRAMA");
Console.WriteLine("Só pode haver um");
Console.ReadLine();
}
else {
Console.WriteLine("Já existe uma instancia rodando");
Console.ReadLine();
}
Vou deixar as explicações tecnicas um pouco de lado e explicar de maneira didatica.
Você vai criar uma aplicação, ela vai ter um "apelido" para o sistema operacional.
Quando for abrir uma nova aplicação o seu programa vai perguntar ao sistema operacional
se existe alguem rodando que tenha o mesmo apelido.
Caso exista ele vai exibir a mensagem "Já existe uma instancia rodando"
Caso não exista ele vai abrir seu programa normalmente.
Espero ter sido claro na explicação.
segunda-feira, 25 de fevereiro de 2008
C# e .NET - Thread - Usando MUTEX para fazer com que seu programa só execute uma instancia
Postado por João Bosco Seixas às 11:11 1 comentários
Marcadores: .NET, C#, Desenvolvimento, Microsoft
quarta-feira, 20 de fevereiro de 2008
C# e .NET - Thread Lock - Trancando recursos para execução de threads
Esse texto pode ser melhor visualizado na pagina da Inteligência Digital.
Para acessa-lo, basta clicar aqui.
As vezes é necessario que suas Threads acessem o mesmo objetos e modifiquem valores nesses objetos.
Porém se você estiver trabalhando com um computador multi-processado, por vezes os resultados serão erradospois uma thread vai desfazer o que a outra já fez.
Vou explicar melhor essa historia.
Exemplo Classico:
Temos um contador numa classe X
int contador = 0;
Só existe uma instancia da classe X no seu programa, e toda vez que suas threads fizerem determinada atividade,elas deve incrementar em 1 esse contador.
Nada mais normal do que a classe X possuir um metodo
public void AtualizaContador(){
contador++;
}
Para esse simples exemplo não estamos levando em conta as boas praticas e questões de encapsulamentoque são muito importantes também.
Agora num ambiente multi-processado, imagine 2 Threads no mesmo momento tentando fazer a atualização do contador.
Suponto que nesse ponto o contador tenha o valor 10
De maneira generica, para fazer a atualização, os passos dados pelo processador seriam:
- Salvar o valor 10 no registrador do processador
- Incrementar o valor contido no registrador em 1
- retornar o valor para memoria
Voltando ao exemplo...
Se duas Threads pegassem ao mesmo tempo o valor 10
as duas iam incrementar o valor para 11
porem na hora de salvar em memoria, uma delas ia salvar primeiro o valor 11
por consequencia a outra deveria salvar o valor 12 mas isso não acontece,
ela salva o valor 11 novamente por cima do valor 11 que já estava lá
Causando uma inconsistencia nos dados da nossa aplicação.
Temos diversas formas de tratar isso, principalmente porque incrementação é uma operação thread safe,então temos classes e metodos para tratar especificamente dessa situação.
Mas vamos tratar aqui como se fosse uma situação generica.
Dessa forma usaremos o lock do C#
De maneira muito simples de usar, o lock irá bloquear os recursos do objeto até que a thread que está utilizando o trecho do codigo acabe de processa-lo
Teriamos então o seguinte codigo:
public void AtualizaContador(){
lock(this){
contador++;
}
}
o lock recebe como parametro o this que é uma palavra reservada do C# que referencia o objeto em questão.
No caso, como o metodo está dentro da classe X o this então, representa a classe X
É como se a propria classe estivesse se referenciando.
Espero ter conseguido passar um pouco da importancia do lock.
Existem outras formas de fazer isso, mas teriamos que entrar em outras discussões como dead lock e etc...
então trarei isso em um outro post.
Talvez vocês não enxerguem a importancia disso num exemplo simples como esse, mas em ambientes complexos isso toma proporções enormes.
Espero ter ajudado
Até a proxima.
Esse texto pode ser melhor visualizado na pagina da Inteligência Digital.
Para acessa-lo, basta clicar aqui.
Postado por João Bosco Seixas às 10:51 3 comentários
Marcadores: .NET, C#, Desenvolvimento, Microsoft
terça-feira, 19 de fevereiro de 2008
Dica C# - Critical Region - Thread
Quando trabalhamos com threads podemos ter a nescessidade de abortar o processo durante a execução.
Para isso temos o metodo Abort() que é muito simples de se utilizar.
Porém, abortar uma Thread durante sua execução pode levar algum objeto de seu sistemaa um estado de inconsistencia.
Imagine o seguinte cenario:
Você tem as seguintes linhas para serem executadas dentro da sua Thread
MinhaClasse.NomePessoa = "JOAO";
MinhaClasse.Idade = "22";
MinhaClasse.Hobby = "Programação";
Se você lança um comando Abort(), durante a execução de qualquer uma dessas linhas, a thread vai pararimediatamente.
Imagine seu objeto agora ficando somente com o atributo nome.
Esse objeto não servirá para nada, pois os outros dados importantes não estão contidos nele.
Para evitar que uma chamada Abort(), termine a thread de maneira errada, podemos usar os metodos:
BeginCriticalRegion()
e
EndCriticalRegion()
voltando ao nosso exemplo, poderiamos fazer da seguinte forma:
Thread.BeginCriticalRegion();
MinhaClasse.NomePessoa = "JOAO";
MinhaClasse.Idade = "22";
MinhaClasse.Hobby = "Programação";
Thread.EndCriticalRegion();
Desta maneira, se nosso programa chamasse o metodo Abort() da nossa Thread, enquanto fosse processada alguma das linhas entre as chamadas de Thread.BeginCriticalRegion() e Thread.EndCriticalRegion()
A thread irá esperar a execução acabar para depois, mandar o sinal de termino a thread.
O objetivo é fazer com que todas as linhas na região critica sejam executadas de forma atomica, como se fossem apenas uma linha.
Espero que a dica seja proveitosa para alguem.
Postado por João Bosco Seixas às 00:03 0 comentários
Marcadores: .NET, C#, Desenvolvimento, Microsoft