• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

amiloM1425

Semáforos

5 mensagens neste tópico

Olá a todos,

é a primeira vez que estou a trabalhar com semáforos em C#, e também para ser sincero nunca semáforos nunca foi o meu forte.

A questão é a seguinte, tenho uma classe estática que vai guardando informação durante o decorrer da aplicação. A essa classe poderão aceder várias threads, e claro existem zonas criticas. Basicamente estou a fazer um sem.WaitOne() quando vou ler/escrever nas zonas criticas e depois faço o sem.Release(). O problema é que a uma determinada altura fica tudo bloqueado, parece uma situação de Deadlock, fica tudo à espera que haja um release.

Aqui fica a classe, se pudessem dar uma vista de olhos e comentar o que está mal agradecia, pois como já referi há pouco não tenho muita experiência com semáforos.

    class DadosActuais
    {
        static Semaphore sem = new Semaphore(1, 1);

        static ArrayList numeroSerieDesconhecidos = new ArrayList();
        static ArrayList numeroSerieConhecidos = new ArrayList();

        /// <summary>
        /// Adiciona um novo nº de série à lista de nº de série conhecidos
        /// </summary>
        /// <param name="numeroSerie">Nº de série a adicionar</param>
        public static void addNumeroSerieConhecido(string numeroSerie)
        {
            sem.WaitOne();

            numeroSerieConhecidos.Add(numeroSerie);
            
            sem.Release();
        }

        /// <summary>
        /// Adiciona um novo nº de série à lista de nº de série desconhecidos
        /// </summary>
        /// <param name="numeroSerie"></param>
        public static void addNumeroSerieDesconhecido(string numeroSerie)
        {
            sem.WaitOne();

            foreach (string nSerie in numeroSerieDesconhecidos)
            {
                if (nSerie.CompareTo(numeroSerie) == 0)
                    return;
            }
            numeroSerieDesconhecidos.Add(numeroSerie);

            sem.Release();
        }

        /// <summary>
        /// Limpa a lista de nº de série desconhecidos
        /// </summary>
        public static void limpaNumeroSerieDesconhecido()
        {
            sem.WaitOne();

            numeroSerieDesconhecidos.Clear();

            sem.Release();
        }

        /// <summary>
        /// Obtém o indice da posição em que se encontra guardado o nº de série do equipamento
        /// </summary>
        /// <param name="numeroSerie">Nº de série do equipamento</param>
        /// <returns>Devolve o indice em que se encontra guardade o equipamento</returns>
        private static int getIndiceEquipamento(string numeroSerie)
        {
            int i = 0;
            foreach (string nSerie in numeroSerieConhecidos)
            {
                if (nSerie.CompareTo(numeroSerie) == 0)
                    return i;
                i++;
            }
            return i;
        }

        /// <summary>
        /// Guarda os nº de série registados na base de dados
        /// </summary>
        /// <param name="lista">Lista com equipamentos registados na base de dados</param>
        public static void carregaDados(ArrayList listaEq)
        {
            foreach (Equipamento eq in listaEq)
            {
                addNumeroSerieConhecido(eq.numeroSerie);
            }
        }

        /// <summary>
        /// Verifica se o nº de série é de um equipamento conhecido
        /// </summary>
        /// <param name="numeroSerie">Nº de série</param>
        /// <returns>Devolve true caso o nº de série pertença a um equipamento conhecido ou false caso contrário</returns>
        public static bool verificaExisteConhecido(string numeroSerie)
        {
            sem.WaitOne();
            foreach (string nSerie in numeroSerieConhecidos)
            {
                if (nSerie.CompareTo(numeroSerie) == 0)
                {
                    sem.Release();
                    return true;
                }
            }
            sem.Release();
            return false;
        }

        /// <summary>
        /// Verifica se o nº de série é de um equipamento desconhecido
        /// </summary>
        /// <param name="numeroSerie">Nº de série</param>
        /// <returns>Devolve true caso o nº de série pertença a um equipamento desconhecido ou false caso contrário</returns>
        public static bool verificaExisteDesconhecido(string numeroSerie)
        {
            sem.WaitOne();
            foreach (string nSerie in numeroSerieDesconhecidos)
            {
                if (nSerie.CompareTo(numeroSerie) == 0)
                {
                    sem.Release();
                    return true;
                }
            }
            sem.Release();
            return false;
        }
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Na função addNumeroSerieDesconhecido se o if for verdadeiro não estás a libertar o semáforo.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Obrigado pela ajuda. Realmente quando se está demasiado tempo a olhar para o mesmo código já se começa a não ver nada à frente :D

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

O C# não tem um "try .. catch"? Se não tem, podes fazer como eu faço em linguagens que não o têm, por exemplo C:

sem.get
do {
    ....
    if error { error = ... ; break; }
    ...
    if error { error = ... ; break; }
    ...
} while (0);
sem.release

Tás a ver a ideia? Há várias variações conforme a aplicação. E ainda podes "embrulhar" várias partes em macros bonitinhas, nas linguagens que as suportem. Só tens que ter cuidado para não aninhar vários niveis, isto só suporta 1.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Sim, o C# tem Try{ } Catch{ }. Ainda vou ter de fazer o tratamento de excepções. De qualquer forma obrigado pela sugestão.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora