PROBLEMA COM TASK E THREAD
Olá, pessoal estou tento um problema que não sei mais como proceder.
Tenho um sistema que faço tratamento com banco de dados e planilha de excel, porém estou tentando utilizar as Task e/ou Thread para calcular e gravar dados na base de dados baseado na planilha.
Até ai o sistema está processando simultaneamente, mas o maior problema é o meu progressbar que eu preciso incrementar o value.
Ai eu faço o seguinte método em um programinha separado e esse funciona normalmente, perfeitamente
Mas agora no sistema que eu controlo o banco de dados o método invoke não funciona o sistema trava nessa linha e não faz mais nada.
No outro sistema eu faço da seguinte forma
Alguém tem alguma sugestão? Tentei diversas coisas e não tive resultado!
O problema é que se eu faço esse processo em um projeto a parte funciona, conforme primeiro código demonstrado.
Aguardo ansioso pela ajuda no fórum, já estou desesperado e no google não encontrei nada que me direcionasse para o caminho correto.
Tenho um sistema que faço tratamento com banco de dados e planilha de excel, porém estou tentando utilizar as Task e/ou Thread para calcular e gravar dados na base de dados baseado na planilha.
Até ai o sistema está processando simultaneamente, mas o maior problema é o meu progressbar que eu preciso incrementar o value.
Ai eu faço o seguinte método em um programinha separado e esse funciona normalmente, perfeitamente
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim t1 As New Threading.Thread(AddressOf Count)
t1.IsBackground = True
t1.Start(100)
End Sub
Private Sub Count(ByVal Max As Object)
If TypeOf Max Is Integer Then
Count(CInt(Max))
End If
End Sub
[txt-color=#e80000] Private Sub SetLabelText(ByVal text As Integer)
If ProgressBar1.InvokeRequired Then
ProgressBar1.Invoke(New Action(Of Integer)(AddressOf SetLabelText), text)
Else
ProgressBar1.Value = text
End If
End Sub[/txt-color]
Private Sub Count(ByVal Max As Integer)
For i = 1 To Max
SetLabelText(i)
Threading.Thread.Sleep(200)
Next
End Sub
Mas agora no sistema que eu controlo o banco de dados o método invoke não funciona o sistema trava nessa linha e não faz mais nada.
No outro sistema eu faço da seguinte forma
Private Sub ProcessarBanco(obj As IEnumerable(Of DataGridViewRow), sTipo As String, mascaraTGE As Integer, inativarGeral As Boolean)
Dim oTGE As New clsSamTge()
Select Case sTipo
Case [Ô]N[Ô] [ô]Novos
Dim lista = obj _
.Select(Function(s) New clsPrecosTuss With {
.Tuss_3_0 = s.Cells([Ô]Tuss_3_0[Ô]).Value,
.Tuss_2_0 = s.Cells([Ô]Tuss_2_0[Ô]).Value,
.Descricao = s.Cells([Ô]Descricao[Ô]).Value,
.Generico = s.Cells([Ô]Generico[Ô]).Value,
.Fracionamento = s.Cells([Ô]Fracionamento[Ô]).Value,
.Fabricante = s.Cells([Ô]Fabricante[Ô]).Value,
.Cnpj_fabricante = s.Cells([Ô]Cnpj_fabricante[Ô]).Value,
.Registro_anvisa = s.Cells([Ô]Registro_anvisa[Ô]).Value,
.Validade_anvisa = s.Cells([Ô]Validade_anvisa[Ô]).Value,
.Importar = s.Cells([Ô]Importar[Ô]).Value,
.Ativo = s.Cells([Ô]Ativo[Ô]).Value,
.Codigo_referencia = s.Cells([Ô]Codigo_referencia[Ô]).Value,
.Brasindice = s.Cells([Ô]Brasindice[Ô]).Value,
.Principio_ativo = s.Cells([Ô]Principio_ativo[Ô]).Value,
.Qtde_fracionada = s.Cells([Ô]Qtde_fracionada[Ô]).Value,
.Fim_vigencia = s.Cells([Ô]Fim_vigencia[Ô]).Value
})
For Each row In lista
oTGE.InserirTGE(row, DataFechamento.Value, mascaraTGE, inativarGeral)
contagem += 1
Next
Case [Ô]E[Ô] [ô]Existentes
Dim lista = obj _
.Select(Function(s) New clsPrecosTuss With {
.Tuss_3_0 = s.Cells([Ô]Tuss_3_0[Ô]).Value,
.Tuss_2_0 = s.Cells([Ô]Tuss_2_0[Ô]).Value,
.Descricao = s.Cells([Ô]Descricao[Ô]).Value,
.Generico = s.Cells([Ô]Generico[Ô]).Value,
.Fracionamento = s.Cells([Ô]Fracionamento[Ô]).Value,
.Fabricante = s.Cells([Ô]Fabricante[Ô]).Value,
.Cnpj_fabricante = s.Cells([Ô]Cnpj_fabricante[Ô]).Value,
.Registro_anvisa = s.Cells([Ô]Registro_anvisa[Ô]).Value,
.Validade_anvisa = s.Cells([Ô]Validade_anvisa[Ô]).Value,
.Importar = s.Cells([Ô]Importar[Ô]).Value,
.Ativo = s.Cells([Ô]Ativo[Ô]).Value,
.Codigo_referencia = s.Cells([Ô]Codigo_referencia[Ô]).Value,
.Brasindice = s.Cells([Ô]Brasindice[Ô]).Value,
.Principio_ativo = s.Cells([Ô]Principio_ativo[Ô]).Value,
.Qtde_fracionada = s.Cells([Ô]Qtde_fracionada[Ô]).Value,
.Fim_vigencia = s.Cells([Ô]Fim_vigencia[Ô]).Value
})
For Each row In lista
oTGE.AtivarTGE(row.Tuss_3_0, row.Fim_vigencia, mascaraTGE)
contagem += 1
Next
Case [Ô]I[Ô] [ô]Inativos
For Each row In obj
oTGE.AtivarTGE(row.Cells([Ô]tuss_3_0[Ô]).Value, row.Cells([Ô]fim_vigencia[Ô]).Value, mascaraTGE)
contagem += 1
Next
Case [Ô]IN[Ô] [ô]Inativar
Dim c As Integer = Convert.ToInt32(Math.Ceiling(obj.Count() / 500))
For xx = 0 To c - 1
Dim oInativar = obj.Skip(xx * 900).Take(900)
For Each row In oInativar
oTGE.InativarTGE(row.Cells([Ô]tuss_3_0[Ô]).Value, DataFechamento.Value.Date, mascaraTGE, inativarGeral)
contagem += 1
Next
GC.Collect()
Next xx
End Select
End Sub
[txt-color=#e80000] Private Sub UpdateProgres(ByVal _value As Integer)
If pbProgresso.InvokeRequired Then
pbProgresso.Invoke(New Action(Of Integer)(AddressOf UpdateProgres), _value) [ô]SISTEMA TRAVA AQUI E NÃO FAZ MAIS NADA NA THREAD
Else
pbProgresso.Value = _value
End If
End Sub[/txt-color]
Private Sub btnProcessar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnProcessar.Click
If MessageBox.Show([Ô]Data para Inativar Materiais/Medicamentos será [Ô] & DataFechamento.Value.ToString([Ô]dd/MM/yyyy[Ô]) & [Ô] confima a integração?[Ô], [Ô]Confirmar[Ô], MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) = DialogResult.Yes Then
Dim lsTask As New List(Of Task)
Dim tsk As Task
Dim mascara As Integer = Integer.Parse(cboMascaraTGE.SelectedValue)
Dim inativarGeral As Boolean = chkSomenteItensFimVigencia.Checked
lblFraseAguarde.Text = [Ô]Aguarde... Processando as informações e gravando os dados.[Ô]
Dim Existentes = dgvTuss.Rows.OfType(Of DataGridViewRow).Where(Function(w) w.Cells.Item([Ô]corLegenda[Ô]).Value = [Ô]E[Ô] And Not String.IsNullOrEmpty(w.Cells.Item([Ô]fim_vigencia[Ô]).Value))
Dim Novos = dgvTuss.Rows.OfType(Of DataGridViewRow).Where(Function(w) w.Cells.Item([Ô]corLegenda[Ô]).Value = [Ô]N[Ô])
Dim Inativos = dgvTuss.Rows.OfType(Of DataGridViewRow).Where(Function(w) w.Cells.Item([Ô]corLegenda[Ô]).Value = [Ô]I[Ô] And String.IsNullOrEmpty(w.Cells([Ô]fim_vigencia[Ô]).Value))
Dim Inativar = dgvTuss.Rows.OfType(Of DataGridViewRow).Where(Function(w) w.Cells.Item([Ô]corLegenda[Ô]).Value = [Ô]IN[Ô])
pbProgresso.Maximum = (Existentes.Count() + Novos.Count() + Inativos.Count() + Inativar.Count())
pbProgresso.Value = 0
contagem = 0
pnlAguarde.Visible = True
Application.DoEvents()
[txt-color=#e80000] Dim trdProgress As New Threading.Thread(Sub()
While contagem <= pbProgresso.Maximum
UpdateProgres(contagem)
If (contagem Mod 1000) = 0 Then Application.DoEvents()
Threading.Thread.Sleep(50)
End While
End Sub)
trdProgress.IsBackground = True
trdProgress.Start()[/txt-color]
[ô]tsk = New Task(Function() Processar([Ô]N[Ô], mascara,inativarGeral))
[ô]tsk.Start()
[ô]lsTask.Add(tsk)
[ô]Threading.Thread.Sleep(3000)
tsk = New Task(Sub() ProcessarBanco(Existentes, [Ô]E[Ô], mascara, inativarGeral))
tsk.Start()
lsTask.Add(tsk)
Threading.Thread.Sleep(3000)
[ô]tsk = New Task(Sub() ProcessarBanco(Inativos, [Ô]I[Ô], mascara, inativarGeral))
[ô]tsk.Start()
[ô]lsTask.Add(tsk)
[ô]Threading.Thread.Sleep(3000)
[ô]tsk = New Task(Function() Processar([Ô]IN[Ô], mascara,inativarGeral))
[ô]tsk.Start()
[ô]lsTask.Add(tsk)
[ô]Threading.Thread.Sleep(3000)
Task.WaitAll(lsTask.ToArray())
If trdProgress.IsAlive Then trdProgress.Abort()
MessageBox.Show([Ô]Processo Concluido[Ô])
btnLimpar.Enabled = True
pnlAguarde.Visible = False
End If
End Sub
Alguém tem alguma sugestão? Tentei diversas coisas e não tive resultado!
O problema é que se eu faço esse processo em um projeto a parte funciona, conforme primeiro código demonstrado.
Aguardo ansioso pela ajuda no fórum, já estou desesperado e no google não encontrei nada que me direcionasse para o caminho correto.
se tem uma coisa que é chata e comunicação form com Thread.
eu faço assim
Private Sub InserirEventos(eventos As String)
listEventos.Insert(0, eventos)
Me.Invoke(New MethodInvoker(Sub() lstEventos.Items.Insert(0, eventos)))
End Sub
eu faço assim
Private Sub InserirEventos(eventos As String)
listEventos.Insert(0, eventos)
Me.Invoke(New MethodInvoker(Sub() lstEventos.Items.Insert(0, eventos)))
End Sub
exemplos...
https://www.codeproject.com/Articles/449594/Progress-Bars-Threads-Windows-Forms-and-You
https://www.codeproject.com/Articles/449594/Progress-Bars-Threads-Windows-Forms-and-You
Então, mas é ai onde mora o problema! rsrsrs
O .Invoke não está funcionando o sistema cai nessa linha e trava não sai dali, mas também não apresenta erro.
O .Invoke não está funcionando o sistema cai nessa linha e trava não sai dali, mas também não apresenta erro.
bom, eu estou fazendo no meu form
Me.Invoke(New MethodInvoker(Sub() lstEventos.Items.Insert(0, eventos)))
tenta no form em vez do progressbar.
Me.Invoke(New MethodInvoker(Sub() lstEventos.Items.Insert(0, eventos)))
tenta no form em vez do progressbar.
Olhando o seu código me parece estar ocorrendo um Deadlock
Deadlock ocorre mais ou menos da seguinte forma, Thread 1 faz uma operação e então espera que Thread 2 termine algo antes dela continuar, e ao mesmo tempo Thread 2 faz algo que precisa esperar terminar na Thread 1, então ficam as duas travadas, uma esperando a outra.
No seu caso isso acontece da seguinte forma, você tem a Thread Principal, que é onde são criados os forms por padrão, e tem a Thread trdProgress. Pode ter outras threads por causa dos Tasks, mas o problema está mesmo nessas duas.
Então a Thread Principal é a que trata os eventos do seu Form, ela vai pegar o click do botão e disparar a outra trdProgress, até ai tudo bom, o problema deve ser no momento que você chama Task.WaitAll, neste ponto essa Thread vai ficar travada esperando as Tasks terminarem, mas ao mesmo tempo sua trdProgress vai chamar o Invoke no form, e a chamada do Invoke trava até ele terminar de executar, porém o Invoke faz com que o código seja executado na Thread Principal, que está travada e por isso ela não sai dali.
Mas eu diria que no seu caso esse é um péssimo uso de Threads, pois a operação é o que é chamado de [Ô]IO Bound[Ô], é uma operação que está ligada a espera de input ou output, como por exemplo a leitura ou gravação de um banco de dados, onde geralmente não se tem ganho real de performance por rodar em várias threads, e o pior ainda é que você criou uma thread só para atualizar o progress bar, o que nunca deveria ser feito já que a atualização da tela deve ser feita exclusivamente pela thread principal.
Eu diria que o ideal é você usar um background worker já que a única coisa que precisa é não travar a tela enquanto executa essa operação, e usar o report progress para atualizar o progresso.
Deadlock ocorre mais ou menos da seguinte forma, Thread 1 faz uma operação e então espera que Thread 2 termine algo antes dela continuar, e ao mesmo tempo Thread 2 faz algo que precisa esperar terminar na Thread 1, então ficam as duas travadas, uma esperando a outra.
No seu caso isso acontece da seguinte forma, você tem a Thread Principal, que é onde são criados os forms por padrão, e tem a Thread trdProgress. Pode ter outras threads por causa dos Tasks, mas o problema está mesmo nessas duas.
Então a Thread Principal é a que trata os eventos do seu Form, ela vai pegar o click do botão e disparar a outra trdProgress, até ai tudo bom, o problema deve ser no momento que você chama Task.WaitAll, neste ponto essa Thread vai ficar travada esperando as Tasks terminarem, mas ao mesmo tempo sua trdProgress vai chamar o Invoke no form, e a chamada do Invoke trava até ele terminar de executar, porém o Invoke faz com que o código seja executado na Thread Principal, que está travada e por isso ela não sai dali.
Mas eu diria que no seu caso esse é um péssimo uso de Threads, pois a operação é o que é chamado de [Ô]IO Bound[Ô], é uma operação que está ligada a espera de input ou output, como por exemplo a leitura ou gravação de um banco de dados, onde geralmente não se tem ganho real de performance por rodar em várias threads, e o pior ainda é que você criou uma thread só para atualizar o progress bar, o que nunca deveria ser feito já que a atualização da tela deve ser feita exclusivamente pela thread principal.
Eu diria que o ideal é você usar um background worker já que a única coisa que precisa é não travar a tela enquanto executa essa operação, e usar o report progress para atualizar o progresso.
Quer algo descente, profissional mesmo? Use OOP e operações assÃncronas. Threads são para outra coisa...
Bom dia pessoal
Obrigado pelas respostas de todos, consegui fazer alguns ajustes no código que possibilitou chamar o Invoke no meu formulário.
Para que não fique algo vago vou explicar o que eu fiz.
Descobri que quando eu utilizo somente uma unica Thread e/ou Task o Invoke funciona normalmente, porém não consegui identificar um método que me possibilitasse a utilização de múltiplas Thread.
Ao realizar esse processo com múltiplas Thread o Invoke trava, pois está sendo chamada por processamentos diferentes. Ai resolvi deixar as Threads rodando e o progress incrementando pela Thread do formulário. Isso possibilitou o processamento da maneira que eu queria, mas não é a melhor solução.
KERPLUNK, escreveu:
KERPLUNK, você poderia me ajudar com essa situação de métodos async?
Esse sistema que solicitei ajuda é antigo e não dá pra mudar ele para 100% OOP, mas uma parte dele até tem OOP, mas não de uma forma legal.
Acontece que estou precisando iniciar um projeto do zero para centralizar todas as informações, ou seja, um repositório de dados que será consumido de sistemas WEB/DESKTOP/MOBILE. Então vem a pergunta, que tipo de estrutura fazer e como iniciar um projeto desse.
Podemos conversar no whatsapp ou skype? Me manda uma mensagem interna com o seu número ou skype.
Desde já agradeço.
Obrigado pelas respostas de todos, consegui fazer alguns ajustes no código que possibilitou chamar o Invoke no meu formulário.
Para que não fique algo vago vou explicar o que eu fiz.
Descobri que quando eu utilizo somente uma unica Thread e/ou Task o Invoke funciona normalmente, porém não consegui identificar um método que me possibilitasse a utilização de múltiplas Thread.
Ao realizar esse processo com múltiplas Thread o Invoke trava, pois está sendo chamada por processamentos diferentes. Ai resolvi deixar as Threads rodando e o progress incrementando pela Thread do formulário. Isso possibilitou o processamento da maneira que eu queria, mas não é a melhor solução.
KERPLUNK, escreveu:
Citação:Quer algo descente, profissional mesmo? Use OOP e operações assÃncronas. Threads são para outra coisa...
KERPLUNK, você poderia me ajudar com essa situação de métodos async?
Esse sistema que solicitei ajuda é antigo e não dá pra mudar ele para 100% OOP, mas uma parte dele até tem OOP, mas não de uma forma legal.
Acontece que estou precisando iniciar um projeto do zero para centralizar todas as informações, ou seja, um repositório de dados que será consumido de sistemas WEB/DESKTOP/MOBILE. Então vem a pergunta, que tipo de estrutura fazer e como iniciar um projeto desse.
Podemos conversar no whatsapp ou skype? Me manda uma mensagem interna com o seu número ou skype.
Desde já agradeço.
Tópico encerrado , respostas não são mais permitidas