Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

softklin

Threads - continuar execução quando as outras threads terminarem

Mensagens Recomendadas

softklin

Boas pessoal.

Estou aqui a trabalhar um mini-projecto antigo, que tem como objectivo verificar numa lista de links, quais os que estão "mortos". Para tal, resolvi incluir uma pequena funcionalidade no programa, que é um limite de ligações. Como já devem ter adivinhado, estou a fazer com threads, e é aí que tenho o problema.

Basicamente, estou a fazer uma thread por link, com auxilio de um semáforo 'sem' para limitar o número de threads concorrentes e de outro semáforo 'allDone' que irá ser libertado quando todos os links forem verificados:

                // inicializar o semaforo que controla nº threads concorrentes
                int totalCon = (int) numMaxCon.Value;
                sem = new Semaphore(totalCon, totalCon);

                // inicializações...

                foreach (String uri in urlList)
                {                  
                    new Thread(checkUrl).Start(uri);
                }
                
                // aguardar que todas as threads tenham terminado
                allDone.WaitOne();

                fileWrite.Close();
                // mostrar resultados...

A função checkurl, resumidamente, é:

       private void checkUrl(object url)
        {
            // aguardar pelo semaforo
            sem.WaitOne();

            // obter resultados aqui...

            // libertar semaforo allDone quando todos os pedidos forem concluidos
            lock (this)
            {
                jobsDone++;

                if (jobsDone == totalJobs)
                    allDone.Release();
            }

            // libertar semaforo
            sem.Release();
        }

O que me acontece é que o processo fica bloqueado no allDone.WaitOne(), pois se verificar em Debug, o total de trabalhos nunca chega ao total da lista. Já verifiquei as inicializações, e à partida, não deveria falhar. Já andei também à procura do reportProgress ou similar, e não encontro na Thread.

Alguém tem alguma sugestão do que possa estar a fazer mal?


Nick antigo: softclean | Tens um projeto? | Wiki P@P

Ajuda a comunidade! Se encontrares algo de errado, usa a opção "Denunciar" por baixo de cada post.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
DVD

Duas questões:

- Não estás a usar o allDone para mais nada?

- Já viste se as threads estão a terminar todas ou estão presas em algum lugar?

Quanto à primeira questão, se não usares para mais nada escusas de estar a por codigo no checkurl, usa as proprias threads para sincronizar aka join :)

Quanto à segunda parece-me que seja o que está a acontecer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
softklin

Boas DVD, obrigado pela ajuda. O allDone seria um semáforo para controlar quando todas as threads teriam feito o trabalho, mas olhando bem, o incremento não seria thread-safe.

Resolvi usar a tua sugestão dos joins, e ficou da seguinte maneira:

                Thread[] jobs = new Thread[urlList.Length];
                int i = 0;
                foreach (String uri in urlList)
                {                  
                    jobs[i] = new Thread(checkUrl);
                    jobs[i].Start(uri);
                    i++;
                }

                // garantir que todas as threads são executadas antes de avançar
                foreach (Thread t in jobs)
                {
                    t.Join();
                }

Ou seja, basicamente, faço um join por cada thread que executo depois de as lançar, para continuar o código apenas após a execução de todas as threads. Esse problema penso estar resolvido.

Já agora, há problemas de criar tantas threads quanto número de links a verificar? No exemplo que testei, tentei com cerca de 300 links e foi esse o número de threads aberto, agora não sei se haverá alguma implicação em termos de recursos, tens algum conselho neste caso?


Nick antigo: softclean | Tens um projeto? | Wiki P@P

Ajuda a comunidade! Se encontrares algo de errado, usa a opção "Denunciar" por baixo de cada post.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
bruno1234

As threads têm um limite razoável.

Uma maneira simples de gerir isso, é utilizares a ThreadPool:

http://msdn.microsoft.com/en-us/library/3dasc8as%28VS.80%29.aspx

Se usares o Begin Invoke dos delegates, tb são geridos pela ThreadPool.


Matraquilhos para Android.

Gratuito na Play Store.

https://play.google.com/store/apps/details?id=pt.bca.matraquilhos

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
softklin

Obrigado pela dica bruno1234, mas neste exemplo, como não queria complicar muito, limitei-me a fazer uma coisa muito simples: em vez de criar as threads todas e bloqueá-las após terem sido criadas, resolvi bloquear no momento imediatamente antes da sua criação, no ciclo for. Ficou:

                Thread[] jobs = new Thread[urlList.Length];
                int i = 0;
                foreach (String uri in urlList)
                {        
                    // aguardar pelo semaforo
                    sem.WaitOne();

                    jobs[i] = new Thread(checkUrl);
                    jobs[i].Start(uri);
                    i++;
                }

                // garantir que todas as threads são executadas antes de avançar
                foreach (Thread t in jobs)
                {
                    t.Join();
                }

O número de threads concorrentes fica igual ao número de ligações simultâneas.


Nick antigo: softclean | Tens um projeto? | Wiki P@P

Ajuda a comunidade! Se encontrares algo de errado, usa a opção "Denunciar" por baixo de cada post.

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Triton

Eu não gosto muito de threads, e neste caso podes facilitar o trabalho usando um nível de abstracção. Existe uma coisa chamada asynchronous network programming que normalmente é implementada com threads internamente, mas tem uma interface mais simples para o tipo de coisa que queres.

http://www.codeguru.com/csharp/csharp/cs_network/sockets/article.php/c7695


<3 life

Partilhar esta mensagem


Ligação 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

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.