Estou com um problema serio com uma Thead.
Pessoal estou tentando rodar o TClientDataSet em um Thread mais não consigo veja o meu codigo.
type
TSQL_Thread = class(TThread)
private
FQuery: TClientDataSet;
protected
procedure Execute; override;
public
constructor Create(Query: TClientDataSet);
destructor Destroy; override;
end;
constructor TSQL_Thread.Create(Query: TClientDataSet);
begin
inherited Create(False);
Screen.Cursor := crSQLWait;
FQuery := Query;
FreeOnTerminate := True;
end;
destructor TSQL_Thread.Destroy;
begin
inherited;
Screen.Cursor := crDefault;
end;
procedure TSQL_Thread.Execute;
begin
inherited;
while not Terminated do begin
try
FQuery.Open;
finally
Terminate;
end;
end;
end;
Esse codigo funciona se eu executar um CDS e esperar ele trazer os dados e executar o proximo CDS mais se eu executar dois CDS ao mesmo tempo ele dá AccessViolation
Se eu executar apenas um assim :
TSQL_Thread.Create(CDS1);
Funciona legal agora se eu fizer algo assim :
TSQL_Thread.Create(CDS1);
TSQL_Thread.Create(CDS2);
ai ele dá erro..
O que devo fazer para resolver isso e executar dois ao mesmo tempo ou como fazer uma função que espera trazer os dados do primeiro e já traga os dados do segundo.
type
TSQL_Thread = class(TThread)
private
FQuery: TClientDataSet;
protected
procedure Execute; override;
public
constructor Create(Query: TClientDataSet);
destructor Destroy; override;
end;
constructor TSQL_Thread.Create(Query: TClientDataSet);
begin
inherited Create(False);
Screen.Cursor := crSQLWait;
FQuery := Query;
FreeOnTerminate := True;
end;
destructor TSQL_Thread.Destroy;
begin
inherited;
Screen.Cursor := crDefault;
end;
procedure TSQL_Thread.Execute;
begin
inherited;
while not Terminated do begin
try
FQuery.Open;
finally
Terminate;
end;
end;
end;
Esse codigo funciona se eu executar um CDS e esperar ele trazer os dados e executar o proximo CDS mais se eu executar dois CDS ao mesmo tempo ele dá AccessViolation
Se eu executar apenas um assim :
TSQL_Thread.Create(CDS1);
Funciona legal agora se eu fizer algo assim :
TSQL_Thread.Create(CDS1);
TSQL_Thread.Create(CDS2);
ai ele dá erro..
O que devo fazer para resolver isso e executar dois ao mesmo tempo ou como fazer uma função que espera trazer os dados do primeiro e já traga os dados do segundo.
Luciano_f
Curtidas 0
Respostas
Marcosrocha
16/08/2007
Luciano os CDS estão conectados ao mesmo banco de dados, você pode criar 300 Threads que serão 300 conexões simultâneas. Só não entendi o por que de trazer os dados dos 2 ao mesmo tempo... :?
GOSTEI 0
Luciano_f
16/08/2007
Jovem no meu caso eu não sei é pelo fato do IBobjects não ser
Thread Safe que esta dando esse erro
eu estou usando o RemObjects SDK para trazer os dados
eu sei que o RemOBjects é Multi-Thread
Será que terei que usar outro componente ao inves do IBObjects...
Thread Safe que esta dando esse erro
eu estou usando o RemObjects SDK para trazer os dados
eu sei que o RemOBjects é Multi-Thread
Será que terei que usar outro componente ao inves do IBObjects...
GOSTEI 0
Marcosrocha
16/08/2007
Acredito que não, já que o CDS está na DataAccess....
Mas como Threads são praticamente impossíveis de Debugar, você vai ter que descobrir porque está dando Access Violation...
Eu penso que uma das Threads está matando a outra e por isso access violation, mas não é certeza pois sempre que trabalhei com elas nunca me ocorreu de manipular um CDS nelas...
Mas como Threads são praticamente impossíveis de Debugar, você vai ter que descobrir porque está dando Access Violation...
Eu penso que uma das Threads está matando a outra e por isso access violation, mas não é certeza pois sempre que trabalhei com elas nunca me ocorreu de manipular um CDS nelas...
GOSTEI 0
Luciano_f
16/08/2007
Meu amigo mais me diga a forma como eu criei essa thread está correta???
tem algum erro nela???
Seguinte na verdade se eu executar uma thread e esperar abrir o CDS e executar o proximo CDS não vai dar erro o erro só acontece se eu abrir dois CDS de uma vez.
Eu tentei fazer uma função que esperace abrir o CDS para abrir o proximo mais não consegui o amigo sabe como posso fazer isso???
Grato.
tem algum erro nela???
Seguinte na verdade se eu executar uma thread e esperar abrir o CDS e executar o proximo CDS não vai dar erro o erro só acontece se eu abrir dois CDS de uma vez.
Eu tentei fazer uma função que esperace abrir o CDS para abrir o proximo mais não consegui o amigo sabe como posso fazer isso???
Grato.
GOSTEI 0
Marcosrocha
16/08/2007
Luciano, o seu modo de criação da Thread respeita a herança da classe Thread, logo nao acho que deva ter problemas nela (criação). Sou capaz de apostar que o problema, realmente seja em executar ao mesmo tempo... Quanto a exemplo... não tenho nada para ajudá-lo no momento... Desculpe. :oops:
GOSTEI 0
Martins
16/08/2007
procedure TSQL_Thread.Execute; begin inherited; while not Terminated do begin try FQuery.Open; finally Terminate; end; end;
Esse código é assim mesmo? Esse [b:13445b4e85]Terminate[/b:13445b4e85] aqui está finalizando a Thread é isso?
GOSTEI 0
Luciano_f
16/08/2007
sim meu amigo é isso mesmo
O terminate esta finalizando a Thread.
Mais tanto faz se eu fizer isso aqui
procedure TSQL_Thread.Execute;
begin
inherited;
if Terminated then Exit;
try
FQuery.Open;
finally
Terminate;
end;
end;
Também da o problema
eu precisava fazer um jeito de esperar a Thread terminar para executar uma nova Query eu já tentei varios codigos para isso mais não dá certo.
O terminate esta finalizando a Thread.
Mais tanto faz se eu fizer isso aqui
procedure TSQL_Thread.Execute;
begin
inherited;
if Terminated then Exit;
try
FQuery.Open;
finally
Terminate;
end;
end;
Também da o problema
eu precisava fazer um jeito de esperar a Thread terminar para executar uma nova Query eu já tentei varios codigos para isso mais não dá certo.
GOSTEI 0
Massuda
16/08/2007
O terminate esta finalizando a Thread.
O TThread.Terminate existe para que outras threads possam encerrar a thread; ele simplesmente faz TThread.Terminated = True. Não faz muito sentido chamar TThread.Terminate de dentro da thread. A thread é encerrada quando TThread.Execute termina.eu precisava fazer um jeito de esperar a Thread terminar...
A forma mais simples é usar TThread.WaitFor. Seria algo assim...with TSQL_Thread.Create(CDS1) do WaitFor;
Com relação ao Access Violation: isso pode ocorrer se seu código estiver usando um objeto que ainda não foi criado ou que já foi destruído.
GOSTEI 0
Luciano_f
16/08/2007
Realmente se vai congelar não resolve, eu já quero usar Thread justamente para o sistema não ficar travado..
Não teria outra forma de eu poder aguardar a Thread Terminar
Não teria outra forma de eu poder aguardar a Thread Terminar
GOSTEI 0
Luciano_f
16/08/2007
Pessoal eu fiz um codigo aqui que esta case dando certo.
constructor TSQL_Thread.Create(Query: TClientDataSet);
begin
inherited Create(False);
vTerminou := True;
Screen.Cursor := crSQLWait;
FQuery := Query;
FreeOnTerminate := True;
end;
destructor TSQL_Thread.Destroy;
begin
inherited;
Screen.Cursor := crDefault;
Terminate;
vTerminou := False;
end;
procedure TSQL_Thread.Execute;
begin
inherited;
FQuery.Open;
end;
procedure TFrmConsultaCliente.Button1Click(Sender: TObject);
begin
while (CDS1.Active = False) do begin
Application.ProcessMessages;
if (vTerminou = false) then
TSQL_Thread.Create(CDS1);
end;
while (CDS2.Active = False) do begin
Application.ProcessMessages;
if (vTerminou = false) then
TSQL_Thread.Create(CDS2);
end;
End;
A variavel vTerminou está declarada na sessão Private
agora o erro que acontece uma vez ou outra é o seguinte
EInvalidOperation : Canvas does not allow drawing.
O que fazer para resolver esse erro ????
constructor TSQL_Thread.Create(Query: TClientDataSet);
begin
inherited Create(False);
vTerminou := True;
Screen.Cursor := crSQLWait;
FQuery := Query;
FreeOnTerminate := True;
end;
destructor TSQL_Thread.Destroy;
begin
inherited;
Screen.Cursor := crDefault;
Terminate;
vTerminou := False;
end;
procedure TSQL_Thread.Execute;
begin
inherited;
FQuery.Open;
end;
procedure TFrmConsultaCliente.Button1Click(Sender: TObject);
begin
while (CDS1.Active = False) do begin
Application.ProcessMessages;
if (vTerminou = false) then
TSQL_Thread.Create(CDS1);
end;
while (CDS2.Active = False) do begin
Application.ProcessMessages;
if (vTerminou = false) then
TSQL_Thread.Create(CDS2);
end;
End;
A variavel vTerminou está declarada na sessão Private
agora o erro que acontece uma vez ou outra é o seguinte
EInvalidOperation : Canvas does not allow drawing.
O que fazer para resolver esse erro ????
GOSTEI 0
Marcosrocha
16/08/2007
Luciano uma vez eu utilizei uma Thread para executar uma rotina pesada no sistema. O problema é que a Thread usava o mesmo IBDataBase da aplicação logo, ao executar a rotina ele fazia com que a aplicação travasse também.
GOSTEI 0
Luciano_f
16/08/2007
McBlade
De inicio eu pensei que fosse esse o meu problema mais não é pois
tanto o IBobjects como o RemOBjects são Thread Safe
Na verdade agora eu preciso saber como resolver o erro
[b:10aaf47db6] EInvalidOperation : Canvas does not allow drawing. [/b:10aaf47db6]
Pois o codigo de espera que eu fiz esta funcionando e não é toda hora que esse erro acontece.
Luciano uma vez eu utilizei uma Thread para executar uma rotina pesada no sistema. O problema é que a Thread usava o mesmo IBDataBase da aplicação logo, ao executar a rotina ele fazia com que a aplicação travasse também.
De inicio eu pensei que fosse esse o meu problema mais não é pois
tanto o IBobjects como o RemOBjects são Thread Safe
Na verdade agora eu preciso saber como resolver o erro
[b:10aaf47db6] EInvalidOperation : Canvas does not allow drawing. [/b:10aaf47db6]
Pois o codigo de espera que eu fiz esta funcionando e não é toda hora que esse erro acontece.
GOSTEI 0
Marcosrocha
16/08/2007
[b:427f99b83d] EInvalidOperation : Canvas does not allow drawing. [/b:427f99b83d]
Já tentou comentar o [b:427f99b83d]Application.ProcessMessages[/b:427f99b83d]?
Porque não tem lógica receber essa mensagem, porém o único método que você está utilizando que possívelmente chama Canvas é o ProcessMessages...
GOSTEI 0
Luciano_f
16/08/2007
Sim eu já fiz isso mais com o
Application.ProcessMessages Comentado
não funciona simplesmente o codigo não funciona
while (CDS2.Active = False) do begin
//Application.ProcessMessages;
if (vTerminou = false) then
TSQL_Thread.Create(CDS2);
end;
a Thread não funciona ela simplesmente para dentro da
constructor TSQL_Thread.Create(Query: TClientDataSet);
begin
inherited Create(False);
vTerminou := True;
Screen.Cursor := crSQLWait;
FQuery := Query; // é executado até aqui e não vai mais .....
// só com ProcessMessages para funcionar
FreeOnTerminate := True;
end;
Application.ProcessMessages Comentado
não funciona simplesmente o codigo não funciona
while (CDS2.Active = False) do begin
//Application.ProcessMessages;
if (vTerminou = false) then
TSQL_Thread.Create(CDS2);
end;
a Thread não funciona ela simplesmente para dentro da
constructor TSQL_Thread.Create(Query: TClientDataSet);
begin
inherited Create(False);
vTerminou := True;
Screen.Cursor := crSQLWait;
FQuery := Query; // é executado até aqui e não vai mais .....
// só com ProcessMessages para funcionar
FreeOnTerminate := True;
end;
GOSTEI 0
Luciano_f
16/08/2007
Pessoal minha solução foi a seguinte ::::
destructor TSQL_Thread.Destroy;
begin
inherited;
Terminate;
end;
procedure TSQL_Thread.Execute;
begin
inherited;
if Terminated then Exit;
try
FQuery.Close;
FQuery.Open;
except
// dentro desse Except não tem codigo algum
// sei que não é certo mais não tive outra alternativa
// a falta disso gera o erro
end;
end;
procedure Proc_ExecQuery(CDS: TClientDataSet);
var Qy_Th: TSQL_Thread;
begin
Qy_Th := TSQL_Thread.Create(CDS);
while (not CDS.Active) and (not Qy_Th.Terminated) do
Application.ProcessMessages;
end;
Eu chamo os CDS com a procedure acima.
Proc_ExecQuery(CDS1);
e Agora não tenho mais erro algum.
e posso executar varios CDS mais sempre vai ter uma espera para abrir os CDS, assim vai abrindo um de cada vez e não congela o aplicativo.
destructor TSQL_Thread.Destroy;
begin
inherited;
Terminate;
end;
procedure TSQL_Thread.Execute;
begin
inherited;
if Terminated then Exit;
try
FQuery.Close;
FQuery.Open;
except
// dentro desse Except não tem codigo algum
// sei que não é certo mais não tive outra alternativa
// a falta disso gera o erro
EInvalidOperation : Canvas does not allow drawing.
end;
end;
procedure Proc_ExecQuery(CDS: TClientDataSet);
var Qy_Th: TSQL_Thread;
begin
Qy_Th := TSQL_Thread.Create(CDS);
while (not CDS.Active) and (not Qy_Th.Terminated) do
Application.ProcessMessages;
end;
Eu chamo os CDS com a procedure acima.
Proc_ExecQuery(CDS1);
e Agora não tenho mais erro algum.
e posso executar varios CDS mais sempre vai ter uma espera para abrir os CDS, assim vai abrindo um de cada vez e não congela o aplicativo.
GOSTEI 0
Marcosrocha
16/08/2007
É isso aí Luciano, quebrando a cabeça que conseguimos solucionar nossos problemas e parabéns por ter postado a solução para ajudar quem passou/passa/passará pelo mesmo problema que você... :wink:
O problema de se ter um except sem código, principalmente na thread, é que ao obter uma except a thread simplesmente pára... Logo você não saberá se deu erro ou não, mas isso depende muito da aplicação dela no programa... Até a próxima! 8)
O problema de se ter um except sem código, principalmente na thread, é que ao obter uma except a thread simplesmente pára... Logo você não saberá se deu erro ou não, mas isso depende muito da aplicação dela no programa... Até a próxima! 8)
GOSTEI 0
Luciano_f
16/08/2007
Interessante meu colega
Eu coloquei um RecordCount nos CDS
tirei o Try Except dei um Count via SQL IBExpert em duas tabelas
e executei quando deu o erro eu fui em recordCount para ver se tinha perdido algum registro devido o erro, e para minha surpresa não perdeu registro algum, todos os registros estavam lá, eu fiz isso varias vezes e sempre a mesma coisa, assim parece que o erro é logo após carregar todos os registro, extranho o colega não acha ???
E grato pela atenção e ajuda de todos.
mcblade
Eu coloquei um RecordCount nos CDS
tirei o Try Except dei um Count via SQL IBExpert em duas tabelas
e executei quando deu o erro eu fui em recordCount para ver se tinha perdido algum registro devido o erro, e para minha surpresa não perdeu registro algum, todos os registros estavam lá, eu fiz isso varias vezes e sempre a mesma coisa, assim parece que o erro é logo após carregar todos os registro, extranho o colega não acha ???
E grato pela atenção e ajuda de todos.
GOSTEI 0