Programa com thread só funciona na primeira vez

Programação C em geral

Moderadores: 51, guest2003

Programa com thread só funciona na primeira vez

Mensagempor __JEREK__ » 10 Dez 2006 10:46

Olá galera, estou tentando entender threads e esta dando um erro aqui não consigo
entender onde esta o problema. Fiz esse programa de teste que tem a função de
contar até 50 e mostrar o resultado na tela. Ele funciona na primeira vez que aperto
o botão, na segunda que aperto o botão não faz nada.

Código: Selecionar todos
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TMultLinha *MultLinha;
int tempo=100;

int conta=0;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
        Form1 -> Label1 -> Caption = "Começou!";  // Quando apertado o botão1 mostra no label1
                                                  // a palavra começou

    conta = 0;                                 //  Zera a variável conta para que comece a contagem
                                               //  apartir do zero


        MultLinha->Resume();                      // inicia o thread
}

//---------------------------------------------------------------------------------------------------------------------------------------
//Inicializa o construtor da classe TMultlinha.
__fastcall TMultLinha::TMultLinha(bool CreateSuspended) : TThread(CreateSuspended)
{
}

//---------------------------------------------------------------------------

void __fastcall TMultLinha::Execute()
{

//conta = 0;

    while(conta<49)                            // Enquanto a variável conta for menor que 49...
    {

        conta++;                               // ...incrementa o valor de conta...

        Form1->Label2->Caption = conta;        // ... mostra o valor de conta no label2

        Sleep(tempo);                          // ... espera um tempo e se ainda conta for menor que 50
                                               // volta ao inícil do laço while

    }                                          // Fim do laço while

    Form1 -> Label1 -> Caption = "Terminou!!"; // Quando termina a contagem mostra na label1 que terminou
}

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{

    MultLinha = new TMultLinha(true);          // Aloca memória para o thread
    MultLinha->Priority = tpNormal;            // Define a prioridade.

}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
    MultLinha->Suspend();                      // Finaliza o thread
}
//---------------------------------------------------------------------------


coloquei no arquivo .h a classe

Código: Selecionar todos
class TMultLinha : public TThread
{
    private:
    protected:
             void __fastcall Execute();
    public:
             __fastcall TMultLinha(bool CreateSuspended);
};


minha dúvida é, porque quando a contagem vai até o final (49), eu não consigo iniciar novamente se eu reseto todas as variáveis??

tem mais alguma coisa que deva fazer para poder funcionar??

outra coisa, tentei colocar um ShowMessage mas deu erro, não posso usar essa função com thread??

valeu galera!!!
__JEREK__
Byte
 
Mensagens: 216
Registrado em: 11 Out 2006 17:53
Localização: BA

Mensagempor Red Neck Guy » 10 Dez 2006 11:17

Pq o código dentro da thread é executado como se fosse uma função normal, ou seja, ela executa o teu loop while e como a condição após 49 deixa de ser verdadeira a função acaba.

Para fazer um thread rodar "para sempre" deve-se fazer assim:


for(;;){

//código que será executado na thread


}

Eu costumo fazer assim:

for(;flagThreadAtiva;){

//código da thread

}

pois daí esse flagThreadAtiva eu controlo atraves da outra thread, pois senão quando o programa acaba a parte da thread continua na memória.
ASM51 descanse em paz!
Avatar do usuário
Red Neck Guy
Dword
 
Mensagens: 1968
Registrado em: 12 Out 2006 22:24

Mensagempor __JEREK__ » 10 Dez 2006 11:52

Oi Aquino, valeu pela resposta rápida!!!!

Quer dizer que as variáveis dentro de um thread não são zeradas??
por exemplo essa variável conta vai até 50 e eu não consigo resetar
ela??

Aquino, tentei criar uma nova classe (multilinha2) mas da erro, tentei
fazer como vc disse, criar uma nova classe de thread e colocar
ativa_threda = 0;' dentro mas qual a diferença entre zerar a variável
ativa_thred no botão de inícil e zerar atravez de outro thread (ou
sera que entndi tudo errado?? hehehe)



Código: Selecionar todos
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TMultLinha *MultLinha;
int tempo=100;

int conta=0;
int ativa_thread=0;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
        Form1 -> Label1 -> Caption = "Começou!";  // Quando apertado o botão1 mostra no label1
                                                  // a palavra começou

        conta = 0;                                //  Zera a variável conta para que comece a contagem
                                                  //  apartir do zero
        ativa_thread = 1;



        MultLinha->Resume();                      // inicia o thread
}

//---------------------------------------------------------------------------------------------------------------------------------------
//Inicializa o construtor da classe TMultlinha.
__fastcall TMultLinha::TMultLinha(bool CreateSuspended) : TThread(CreateSuspended)
{
}


//---------------------------------------------------------------------------------------------------------------------------------------
//Inicializa o construtor da classe TMultlinha.
__fastcall TMultLinha2::TMultLinha2(bool CreateSuspended) : TThread(CreateSuspended)
{
}

//---------------------------------------------------------------------------

void __fastcall TMultLinha2::Execute()
{

ativa_thread =0;

}


//---------------------------------------------------------------------------

void __fastcall TMultLinha::Execute()
{

//conta = 0;

   // while(conta<49)                            // Enquanto a variável conta for menor que 49...
   for(;ativa_thread;)
    {

        conta++;                               // ...incrementa o valor de conta...

        Form1->Label2->Caption = conta;        // ... mostra o valor de conta no label2

        Sleep(tempo);                          // ... espera um tempo e se ainda conta for menor que 50
                                               // volta ao inícil do laço while
        if(conta == 50)
        {
                ativa_thread =0;
                MultLinha2->Resume();                      // inicia o thread    <-------------------Erro 'Undefinide symbol'
        }


      //   MultLinha->Resume();                      // inicia o thread

    }                                          // Fim do laço while

    ativa_thread = 0;
    Form1 -> Label1 -> Caption = "Terminou!!"; // Quando termina a contagem mostra na label1 que terminou
}

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{

    MultLinha = new TMultLinha(true);          // Aloca memória para o objeto.
    MultLinha->Priority = tpNormal;            // Define a prioridade.

}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{


    MultLinha->Suspend();                      // Finaliza o thread
}
//---------------------------------------------------------------------------



Aquino. mais uma vez obrigado pela resposta!!!
__JEREK__
Byte
 
Mensagens: 216
Registrado em: 11 Out 2006 17:53
Localização: BA

Mensagempor Red Neck Guy » 10 Dez 2006 13:04

Não é nada a ver com o fato de não zerar uma variavel, faça um paralelo com a função main, se dentro dela não houver nenhum laço de repetição o teu programa será executado apenas uma vez e terminará, é isso que ocorre...
ASM51 descanse em paz!
Avatar do usuário
Red Neck Guy
Dword
 
Mensagens: 1968
Registrado em: 12 Out 2006 22:24

Mensagempor __JEREK__ » 10 Dez 2006 14:00

Ah!!!!!!!!!!!!! entendi!! poxa, se era só isso por que eles não falam logo o que esse tal de thread???

Valeu Aquino, agora tá funcionando legal!!!

vou deixar o código aqui se alguem tiver a mesma dúvida depois dessa explicação sua acho que vai pegar rapidinho o conseito de thread!!!


Aqui é o Form1, eu só coloquei o objeto Tabsheet para ter certeza que o thread esta funcionando mesmo e não travando o formulario.

Imagem

Código do Unit.ccp
Código: Selecionar todos
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

TMultLinha *MultLinha;                                // cria Mutilinha , como se fosse Form1
int tempo=100;                                        // tempo de Sleep
int conta=0;                                          // variável conta

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}

//---------------------------------------------------------------------------
//Inicializa o construtor da classe TMultlinha.
__fastcall TMultLinha::TMultLinha(bool CreateSuspended) : TThread(CreateSuspended)
{
}

//---------------------------------------------------------------------------

void __fastcall TMultLinha::Execute()
{


  while(true)                                         // Vida do thread
    {
        conta++;                                      // ...incrementa o valor de conta...

        if(conta<50)                                  // ... se o valor de conta for menor que 50...
        {

           Form1->Label2->Caption = conta;            // ... mostra o valor de conta no label2...

        }

        if(conta==50)                                 // ... se o valor de conta for igual a 50 ...
        {

           Form1 -> Label1 -> Caption = "Terminou!!"; // ... mostra na label1 que terminou

        }

        Sleep(tempo);                                 // ... quando termina o processo o programa entra
                                                      // em Sleep, ou seja não fica processando nada e
                                                      // tomando memória mas tambem não termina

    }                                                 // Fim do laço while

}
//---------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
        Form1 -> Label1 -> Caption = "Começou!";      // Quando apertado o botão1 mostra no label1
                                                      // a palavra começou

        conta = 0;                                    // Zera a variável conta para que comece a contagem
                                                      // apartir do zero

        MultLinha->Resume();                          // inicia o thread
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    MultLinha->Suspend();                             // Finaliza o thread
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    MultLinha = new TMultLinha(true);                 // Aloca memória para o thread
    MultLinha->Priority = tpNormal;                   // Define a prioridade.
}
//---------------------------------------------------------------------------


Código do Unit.h
Código: Selecionar todos
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
//---------------------------------------------------------------------------
class TMultLinha : public TThread             // Acresentar classe do thread
{
    private:
    protected:
             void __fastcall Execute();
    public:
             __fastcall TMultLinha(bool CreateSuspended);
};
//----------------------------------
class TForm1 : public TForm
{
__published:   // IDE-managed Components
        TButton *Button1;
        TButton *Button2;
        TLabel *Label1;
        TLabel *Label2;
        TPageControl *PageControl1;
        TTabSheet *TabSheet1;
        TTabSheet *TabSheet2;
        TTabSheet *TabSheet3;
        void __fastcall Button1Click(TObject *Sender);
        void __fastcall Button2Click(TObject *Sender);
        void __fastcall FormCreate(TObject *Sender);
private:   // User declarations
public:      // User declarations
        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif


Aquino, muito obrigado pela exlicação cara, valeu mesmo!!

abraços e boa sorte!!!
__JEREK__
Byte
 
Mensagens: 216
Registrado em: 11 Out 2006 17:53
Localização: BA

Mensagempor Red Neck Guy » 10 Dez 2006 14:11

Só um pequeno detalhe.
Como tu colocaste um while(true) dentro do da thread quando o teu programa acabar a área de memória alocada pela tua aplicação no windows continuará reservada, o correto é implementar o flag como eu havia mencionado e no método destrutor da classe pai zerá-lo, assim quando o programa acabar a thread morre.
ASM51 descanse em paz!
Avatar do usuário
Red Neck Guy
Dword
 
Mensagens: 1968
Registrado em: 12 Out 2006 22:24

Mensagempor CCandido » 10 Dez 2006 15:48

achei que é melhor maneira de usar Thread

cpp code
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------
HANDLE hThread; DWORD dwID;
bool Tterminar=true;
DWORD WINAPI ThreadFunc(LPVOID lParam);
//---------------------------------------------------------

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
hThread = CreateThread(NULL,0,ThreadFunc,NULL,0,&dwID);

}
//--------------------------------------------------------------------------
//---------------------------------------------------------------------------
DWORD WINAPI ThreadFunc(LPVOID lParam){

while( Tterminar ){

aqui seus codigos..............

}


}

//----------------------
aqui FormClose ou Sair click pra finalizar

Tterminar=false;
CCandido
Byte
 
Mensagens: 120
Registrado em: 12 Out 2006 12:54
Localização: Londrina-PR

Mensagempor __JEREK__ » 10 Dez 2006 16:37

CCandido, muito obrigado pela sua contribuição, já me deu outras idéias.

eu gostaria de saber uma coisa se for possível, como eu sei se o thread realmente foi fechado e a area de memória que foi reservada esta livre, existe algum jeito??

Valeu galera, muito obrigado!!!
__JEREK__
Byte
 
Mensagens: 216
Registrado em: 11 Out 2006 17:53
Localização: BA

Mensagempor CCandido » 10 Dez 2006 23:52

cara depois disto aqui ( Tterminar=false; ) ela finaliza mesmo!
só que tem que ser na saida do programa
ex: no Sair_click e no FormClose

não testei ainda mas axo que pode finalizar uma T, e abrir outra e vice verça.
em caso de seu pg. poder entrar num loopforerer use truques
ex: uma tecla que finalize a T. e depois o programa.
esta parte que eu mais gosto (waxi_dog_forçado).
qquer coisa use o msn ccandido_@hotmail.com
tLA,
CCandido
Byte
 
Mensagens: 120
Registrado em: 12 Out 2006 12:54
Localização: Londrina-PR

Mensagempor chipselect » 11 Dez 2006 16:13

Como você está usando o CBuilder, dê uma olhada também na função Synchronize() para que o código da thread atualize de forma segura os componentes da VCL e etc...

Quando suas threads (o main roda numa) ficarem complexas e forem trocar dados, veja também o uso de semáforos ou seções críticas. Você pode usar a TThreadList no lugar de uma TList, que tem muita coisa pronta.
chipselect
Word
 
Mensagens: 744
Registrado em: 16 Out 2006 18:50


Voltar para Visual C++/C/C++/C#

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante

x