Ir para conteúdo
Fórum Script Brasil
  • 0

(Resolvido) Usando Timer/Thread


Xistyle

Pergunta

Amigos, boa tarde!

Estou com uma dúvida e não faço idéia por onde começar as pesquisas. Espero que possam me dar uma luz, exemplos de códigos, enfim a ajuda de sempre que dão.

Estou desenvolvendo um Agendador de tarefas para um aplicativo. O aplicativo final executa uma verificação em arquivos, então é um processo bem demorado. O agendador então deverá ficar em background enquanto executado e, de tempos em tempos, verificar se a tarefa do aplicativo final foi finalizada para iniciar a tarefa seguinte.

O agendador possui um parâmetro que é o intervalo de tempo que será verificado se a tarefa do aplicativo final foi finalizada ou não. Agora, como faço para criar esse timer que irá verificar de tempos em tempos? Li em algumas fontes de pesquisa rápida que deveria usar thread, mas não faço idéia de como usá-la.

Abraços camaradas.

Link para o comentário
Compartilhar em outros sites

8 respostass a esta questão

Posts Recomendados

  • 0

Lucas, obrigado pela resposta.

Na verdade já tenho alguns processos que realizam o cadastramento das tarefas que serão agendadas. Preciso apenas saber como terei um Timer executando 24/7 e de x em x tempo verificando se determinada foi finalizada para iniciar a seguinte.

Não sou familiarizado com C#, por isso não entendi bem a lógica do código.

Link para o comentário
Compartilhar em outros sites

  • 0

Olha, sem saber exatamente como está seu programa, fica dificil sugerir uma solução.

Você sabe exatamente quantas tarefas são? As tarefas já estão definidas desde a execução do programa ou são geradas aleatóriamente durante sua execução?

De qualquer forma, com as informações que eu tenho, eu faria diferente. Ao invés de criar um "timer" que vai ficar verificando a cada 5 minutos por exemplo se a tarefa foi concluída, eu simplesmente chamaria o método que inicia a próxima tarefa ao final da anterior.

Editado por Lucas Phillip
Link para o comentário
Compartilhar em outros sites

  • 0

O problema é que eu não tenho um número fixo de tarefas. Imagine que eu agende essa verificação de arquivos no dia de hoje para 4 pastas, por exemplo.

A primeira pasta foi agendada para iniciar as 11:00, a segunda as 15:00, a terceira as 19:00 e a quarta as 22:00. O timer tem que primeiramente verificar se existe alguma tarefa agendada anteriormente que não foi finalizada, por exemplo, uma tarefa de hoje que foi agendada na madrugada e não foi concluída.

Caso ainda esteja em execução, não fará nada. Caso a tarefa anterior não esteja rodando, chamará a próxima tarefa a ser executada, no caso a agendada para as 11h.

Esse timer irá chamar um outro aplicativo que efetivamente irá executar a verificação nas pastas. Isso já está pronto. Contudo, varia a quantidades de tarefas e tempo de uma pasta para outra. Pode ser que a primeira pasta leve 7 horas para terminar a tarefa. Ou seja, a segunda tarefa que seria executada as 15h, será executada apenas às 18h. Mesmo assim, pode ser que o volume de arquivos da segunda pasta seja menor, e leve apenas 1:30h para executar a tarefa, iniciando a terceira tarefa as 19:30h.

Se tiver alguma idéia de como eu posso criar o timer já é de grande ajuda. Ou outras idéias de como implementar esse timer, fico muito grato.

Abraço e obrigado antecipadamente.

Link para o comentário
Compartilhar em outros sites

  • 0

Olha, eu vou te passar uma maneira bem genérica, que deve conseguir o que você precisa. Não é nem de longe a melhor solução.. Mas, para fazer a melhor solução eu precisaria conhecer seu código.

Crie um campo estático booleano chamado IsRunning.

Antes de cada método, mande um loop confirir se IsRunning está como true. Se estiver, mande a thread dormir por X minutos. Se estiver false, defina como true e inicie o processo. Quando o processo terminar, lembre-se de passar IsRunning para false

Dessa maneira, enquanto um algo estiver sendo processado, os outros terão de esperar. Mas isso é cheio de falhas.. Por exemplo.. se um processo demorar muito e 2 outros iniciarem, não haverá garantias que a ordem de inicio será seguida. O terceiro poderá iniciar antes do segundo.

Agora, como eu falei antes, eu faria sem usar timers. Algo assim:

Crie uma lista do tipo Queue estática. Adicione os métodos (através de delegate) a essa queue. Confira se a queue possuia 0 valores. Se sim, inicie o primeiro processo utilizando o método Peek() de Queue.

Quando esse primeiro processo acabar, você retira um valor da queue e dá um novo Peek(), que no caso será o proximo metodo a ser executado. Assim, se você colocar 10 metodos na lista, um irá iniciar assim que o anterior acabar. Se você adicionar mais metodos à lista enquanto ela executa, eles serão chamados assim que chegar a vez deles. Se a lista ficar vazia e você adicionar um novo método, ele será executado no mesmo instante.

Link para o comentário
Compartilhar em outros sites

  • 0

Então Lucas, estou fazendo diferente. Tenho uma tabela guarda as tarefas agendadas. Essa tabela possui uma flag, que seria o IsRunning que sugeriu.

Coloquei um Timer do Windows Form mesmo (estava preocupado se o contador ia parar enquanto eu cadastrasse uma nova tarefa ou excluísse uma já existente, mas ele não pára).

Com isso eu consigo fazer o cálculo para saber qual será a próxima verificação de acordo com o que o usuário informou. Assim, faço um novo cálculo para ter no evento Tick do Timer o tempo restante para uma nova verificação.

Quando esse contador zera, chamo uma rotina que irá buscar no banco de dados se existe alguma tarefa agendada. Caso exista, não fará nada e o contador irá reiniciar para uma nova verificação.

Caso não exista, faz uma pesquisa no banco pela tarefa mais antiga (dia e hora) após a que acabou de ser executada e chama o outro aplicativo que fará todo o trabalho.

Seguem alguns códigos:

'# Realiza verificações de horário e chama a rotina de verificação de fim de evento agendado
    Private Sub tmrRelogio_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrRelogio.Tick
        Dim ldatTempoParaNovaVerificacao As TimeSpan

        '# Variável do form que irá receber sempre a hora atualizada
        mdatHoraAtual = Now.ToLongTimeString()

        '# É feito o cálculo a partir da mdatProximaVerificacao, que é baseado nos minutos que o usuário escolhe para as verificações
        ldatTempoParaNovaVerificacao = mdatProximaVerificacao.Subtract(mdatHoraAtual)

        lblRelogio.Text = "Próxima verificação em: " & ldatTempoParaNovaVerificacao.ToString

        '# Caso o relógio para a próxima verificação tenha zerado, verifica se o evento atual foi finalizado
        If ldatTempoParaNovaVerificacao.ToString = "00:00:00" Then
            lfcnVerificaExecucao()
        End If

    End Sub



    '# Verifica se existe algum evento agendado. Caso negativo, inicia um evento. 
    '# Caso positivo, apenas aguarda o término deste para iniciar o próximo
    Private Function lfcnVerificaExecucao() As String
        Dim lstrSQL As String
        Dim ldtbDados As DataTable
        Dim lclsConexao As New clsConexao

        lstrSQL = "SELECT   IDIND_EVENTOAGENDADO,       " & Chr(13) & _
                  "         IDIND_STATUSEXECUCAO,                 " & Chr(13) & _
                  "         DATAHORA,                                       " & Chr(13) & _
                  "         SERVIDOR,                                        " & Chr(13) & _
                  "         CELULA,                                             " & Chr(13) & _
                  "         STATUSPROCESSO                             " & Chr(13) & _
                  " FROM VW_EVENTOSAGENDADOS                 " & Chr(13) & _
                  "     WHERE IDIND_STATUSEXECUCAO = " & eStatusExecucao.EmExecucao

        ldtbDados = lclsConexao.RetornaDados(lstrSQL, 0)

        If ldtbDados.Rows.Count > 0 Then

            lfcnVerificaExecucao = "Em execução: " & Format(ldtbDados.Rows(0).Item("DATAHORA"), "dd/MM/yyyy") & _
                                                  " " & ldtbDados.Rows(0).Item("SERVIDOR") & _
                                                  " - " & ldtbDados.Rows(0).Item("CELULA") & _
                                                  " - " & ldtbDados.Rows(0).Item("STATUSPROCESSO")

            mclCalendario.SelectionRange.Start = ldtbDados.Rows(0).Item("DATAHORA")
            Call mclCalendario_DateSelected(Me, Nothing)

        Else

               '# Aqui colocarei o código para chamar o próximo evento a ser executado

        End If

        lclsConexao = Nothing

    End Function

Por enquanto é só um teste, mas acho que irá funcionar.

Link para o comentário
Compartilhar em outros sites

  • 0

Olha, é isso ai mesmo. Maneiras de se fazer, existe milhares. Você desenvolver sua própria lógica é muito melhor do que utilizar a de outra pessoa, pois fica mais fácil de editar e tornar cada vez mais eficiente.

Testa ai. Qualquer dúvida ou problema avisa ai que agente tenta te ajudar no que precisar.

Agora, só uma dica. As strings no .NET são permanentes. Isso quer dizer que depois que você define uma string, ela não pode ser modificada. Pode parecer estranho a principio, porque se você fizer

Dim teste as String = "Ola"

teste = teste & " Lucas!"

funciona. Mas na verdade, você está criando na memória 2 strings. O CLR irá criar uma string Ola, depois irá criar outra string diferente Ola Lucas! Não sei se fui claro, então vou utilizar um exemplo do seu script:

lfcnVerificaExecucao = "Em execução: " & Format(ldtbDados.Rows(0).Item("DATAHORA"), "dd/MM/yyyy") & _
                                                  " " & ldtbDados.Rows(0).Item("SERVIDOR") & _
                                                  " - " & ldtbDados.Rows(0).Item("CELULA") & _
                                                  " - " & ldtbDados.Rows(0).Item("STATUSPROCESSO")

Pode parecer visualmente que você esta criando uma string, mas por baixo dos panos acontece o seguinte:

Nova string: Em execução

Nova string: Em execução Format(ldtbDados.Rows(0).Item("DATAHORA"), "dd/MM/yyyy")

Nova string: Em execução Format(ldtbDados.Rows(0).Item("DATAHORA"), "dd/MM/yyyy") ldtbDados.Rows(0).Item("SERVIDOR")

Nova string: Em execução Format(ldtbDados.Rows(0).Item("DATAHORA"), "dd/MM/yyyy") ldtbDados.Rows(0).Item("SERVIDOR") ldtbDados.Rows(0).Item("CELULA")

Nova string: Em execução Format(ldtbDados.Rows(0).Item("DATAHORA"), "dd/MM/yyyy") ldtbDados.Rows(0).Item("SERVIDOR") ldtbDados.Rows(0).Item("CELULA") ldtbDados.Rows(0).Item("STATUSPROCESSO")

Ou seja, você acaba criando 5 strings atoa. Em um programa simples, isso não faz diferença nenhuma. Só programas com grandes quantidades de processamento, como servidores de empresas é que tem um impacto.

O ideal é utilizar a classe StringBuilder ou o método estático String.Format nesses casos. Como eu falei, no seu programa não faz nenhuma diferença perceptivel. Mas é uma boa prática utilizar uma das duas maneiras :)

Editado por Lucas Phillip
Link para o comentário
Compartilhar em outros sites

  • 0

Uia! Vivendo e aprendendo!

Valeu pela dica Lucas! Não é porque o sistema é pequeno que não custa fazer da forma mais adequada, pra se acostumar sempre. Vou pesquisar e montar da forma correta então.

Se tiver algum problema sobre o agendador volto a postar, caso contrário eu fecho o tópico como [RESOLVIDO].

Obrigado pela força!

Link para o comentário
Compartilhar em outros sites

Participe da discussão

Você pode postar agora e se registrar depois. Se você já tem uma conta, acesse agora para postar com sua conta.

Visitante
Responder esta pergunta...

×   Você colou conteúdo com formatação.   Remover formatação

  Apenas 75 emoticons são permitidos.

×   Seu link foi incorporado automaticamente.   Exibir como um link em vez disso

×   Seu conteúdo anterior foi restaurado.   Limpar Editor

×   Você não pode colar imagens diretamente. Carregar ou inserir imagens do URL.



  • Estatísticas dos Fóruns

    • Tópicos
      152,3k
    • Posts
      652,3k
×
×
  • Criar Novo...