Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Otros entornos y lenguajes > C++ Builder
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 04-03-2008
Ziara Ziara is offline
Miembro
 
Registrado: dic 2007
Posts: 43
Poder: 0
Ziara Va por buen camino
No consigo que el terminate de un thread tenga efecto!!

Hola a todos, no consigo terminar un thread!

tengo creado en un Unit una clase TThread llamado ThreadPackets que se encarga de ir sacando los paquetes que se captura en un ListView.

En el método execute de dicho clase tengo algo estilo..
Código:
while (!Terminated)
{
 //sacar paquetes
}
desde un evento de otra clase distinto llamado Capturar llamo a lo anterior mediante:

Código:
void Capturar::Funcion1()
{

//se abre el dispositivo
//selecciona el dispositivo a sniffar

miThread = new ThreadPackets(adhandle);

}
y ahora creo otro método (función) dentro de la misma clase Capturar para terminar con el thread

Código:
void Capturar::StopThreadPackets()
{
 miThread->Terminate();
}
con esto, cuando en otro Unit donde está mi formulario principal y donde existe un button4 y hago click en él, asociándole lo anterior, teóricamente debería terminar la captura:

Código:
void __fastcall TForm1::Button4Click(TObject *Sender)
{
 Capturar *x = new Capturar();
 x->StopThreadPackets();
 delete x;
}
es decir, cuando ejecuto la aplicación y empieza a ir capturando paquetes e ir mostrandolo en pantalla en el ListView y le doy al botón de terminar captura, pasa de mi... y sigue con la captura.

que estoy haciendo mal u obviando? existe otra alternativa?

gracias
Responder Con Cita
  #2  
Antiguo 04-03-2008
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Pues el error lo tienes aquí:
Código:
void __fastcall TForm1::Button4Click(TObject *Sender)
{
 Capturar *x = new Capturar();
 x->StopThreadPackets();
 delete x;
}
Estas creando un objeto nuevo de la clase Capturar (x) y llamas a una función que utiliza un miembro de esa clase:

Código:
void Capturar::StopThreadPackets()
{
 miThread->Terminate();
}
Pienso que miThread pertenece a la clase Caputrar. miThread es un miembro puntero que si no es un miembro static, ¿a donde apunta al crear un nuevo objeto Capturar?... Pues a un nuevo Thread, probablemente, no conozco más de tu código. Pero es seguro que no apunta al Thread que se está ejecutando, por lo que Terminate() termina con el nuevo Thread y no con el que tu esperabas.

La solución es que tengas controlado el puntero miThread de forma que sea una variable global de Form1, static de la clase Capturar, que lo copies al crear un elemento Capturar o que simplemente Form1 tenga un miembro de la clase Capturar ya creado de forma que no necesites crear uno nuevo para la función Button4Click. En definitiva que sepas que miThread apunta a lo que tu quieres.

Saludos.

Última edición por escafandra fecha: 04-03-2008 a las 23:52:39.
Responder Con Cita
  #3  
Antiguo 05-03-2008
Ziara Ziara is offline
Miembro
 
Registrado: dic 2007
Posts: 43
Poder: 0
Ziara Va por buen camino
Hola de nuevo, ante todo gracias por la pronta respuesta.

Cita:
Pienso que miThread pertenece a la clase Caputrar.
miThread lo tengo definido en el .h de la clase Capturar como:

Código:
class Capturar
{
 private:
           ...
           ThreadPackets *miThread;

 public: 
         ...
};
siempre que en la cabecera del .h tenga
Código:
#include "Unit4.h"
donde Unit4.h es donde tengo mi clase Thread llamado ThredPackets, así puedo usar miThread de forma global dentro de la clase Capturar.

Y más o menos entiendo lo que has mencionado:
Cita:
Form1 tenga un miembro de la clase Capturar ya creado de forma que no necesites crear uno nuevo para la función Button4Click
Ahora he modificado en el Form1 y tengo globalmente el objeto x, ya que lo llamo en dos ocasiones:

1. mediante un botón para empezar la captura de paquetes:
Código:
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 x = new Capturar();
 x->Funcion1(); //aqui dentro es donde llega el momento de capturar llama a miThread = new ThredPackets(adhandle)

}
2.mediante un botón para terminar la captura:
void __fastcall TForm1::Button4Click(TObject *Sender)
{

x->StopThreadPackets();
delete snf;
}

Pero con esto tampoco va... y, cuando pruebo que el puntero miThread sea static en la clase Capturar y pongo en el .h:

Código:
class Capturar
{
 private:
           ...
           ThreadPackets static *miThread;

 public: 
         ...
};
me da un error de:

[Linker Error] Unresolved external 'Capturar::miThread' referenced from C:\DOCUMENTS AND SETTINGS\ADMINISTRADOR\MIS DOCUMENTOS\EXESC\BONITO(1.2)\UNIT3.OBJ

y sin static, me compila bien, seguramente no lo esté poniendo bien, me podeis dar más info sobre lo de poner el puntero static?
Responder Con Cita
  #4  
Antiguo 05-03-2008
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Bien. Yo crearía x al crear Form1 y no con un evento de botón que puede ejecutarse o no a gusto del usuario. x debe ser un miembro de Form1 creado y que se destruya en el destructor de Form1. Pon un punto de parada en miTrhead, para detectar si es tu objeto u otro el que ejecuta Terminate, (puedes controlar si un miembro de valor conocido y esperable lo tiene o no, para saber si efectivamente miThread apunta a tu tarea que se está ejecutando).

Los miembros static de una clase son un poco liosos. Deben estar declarados e inicializados al declarar la clase, pues su valor será el mismo para todos los objetos que existan de esa clase. Y sólo se pueden modificar por funciones también declaradas como static. En tu caso es preferible que x exista en todo momento para contro0lar miThread. El problema está en si quieres que exixtan varias tareas capturar ejecutandose al mismo tiempo. Esto te obliga a crear una matriz de punteros en Form1 y tener todos ellos guardados para ejecutar, en un bucle, por ejemplo x->Terminate().

ANALIZA ESTO: El hecho de que
Código:
void __fastcall TForm1::Button2Click(TObject *Sender)
{
 x = new Capturar();
 x->Funcion1(); //aqui dentro es donde llega el momento de capturar llama a miThread = new ThredPackets(adhandle)

}
significa que cada vez que pulsas Button2, creas y ejecutas una tarea nueva. x apuntará a la última creada, pero las anteriores "se han perdido en memoria", pues no tienes ningún puntero que las referencie. Existirán mientras exista tu aplicación, de forma que no las puedes parar tu sino terminarán según su código programado.

Última edición por escafandra fecha: 05-03-2008 a las 21:31:13.
Responder Con Cita
  #5  
Antiguo 07-03-2008
Ziara Ziara is offline
Miembro
 
Registrado: dic 2007
Posts: 43
Poder: 0
Ziara Va por buen camino
Hola de nuevo,

Cita:
Yo crearía x al crear Form1 y no con un evento de botón que puede ejecutarse o no a gusto del usuario. x debe ser un miembro de Form1 creado y que se destruya en el destructor de Form1.
he hecho lo que me has dicho:

Capturar *x; //variable global

void __fastcall TForm1::FormCreate(TObject *Sender)
{
x = new Capturar(); //crea el objeto
}

..

void __fastcall TForm1::Button4Click(TObject *Sender)
{
x->StopThreadPackets();
}

void __fastcall TForm1::FormDestroy(TObject *Sender)
{
delete x;
}

vale, con esto si le doy al boton de parar sigue sin parar, pero me ha surgido una nueva duda:

en la class Capturar como indiqué anteriormente tengo en el .cpp:

ThreadPackets *miThread;//instancio globalmentre miThread

void Capturar::Funcion1()
{

//se abre el dispositivo
//selecciona el dispositivo a sniffar

miThread = new ThreadPackets(adhandle);

}
y en otro método:

void Capturar::StopThreadPackets()
{
miThread->Terminate();
}
puede que no termine porque al estar en métodos diferentes son dos objetos diferentes? aunque se hayan instanciado globalmente?
Cita:
Pon un punto de parada en miTrhead, para detectar si es tu objeto u otro el que ejecuta Terminate
me podrías decir cómo se hace eso? no controlo muy bien el tema de los puntos de ruptura, si es que te refieres a eso

gracias
Responder Con Cita
  #6  
Antiguo 07-03-2008
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Ahora no veo donde pones en marcha tu thread. No ejecutas Funcion1 en el código que me expones. Digo esto, porque miThtread será creado cada vez que ejecutes Funcion1 y puedes "acumular threads incontrolados".

El hecho de que sea una variable global, en principio no debe influir si la lógica de programación es correcta, aunque al estar programando orientado a objetos, no tiene sentido una variable global que sólo va a utilizar una clase y a la que no se accede desde otro punto.

No se como tienes programada el Thread. Cuando utilizo threads, creo un elemento TThread desde la opción new del Builder. Me crea un prototipo de clase derivada de TThread que yo termino de definir e implementar.

La función Terminate() No termina inmediatamente con el Thread, sino que lo hace tan pronto como sea posible, por lo que la lógica de programación puede influir. Sólo chekeando el valor de Thread->Terminated, sabrás que ha terminado. Para terminar inmediatamente puedes usar la API TerminateThread.

Los puntos de parada los generas al colocar el cursor un una línea de código y pulsar F5. Cuando el código que se ejecuta llege a ese punto, se para y puedes comprobar valores, ejecutar paso a paso....Debugear.

En definitiva:

1) Controla que tu puntero miThread apunta realmente a lo que tu quieres.

2) Ejecuta el código que tengas en la función miThread->Execute() paso a paso y comprueba que no penetras en un bucle sin fin.

3) Recuerda la API TerminateThread para terminar a la fuerza, claro que esto te puede hacer perder datos.

Saludos.

Última edición por escafandra fecha: 07-03-2008 a las 19:41:10. Razón: Mal funcionamiento del editor
Responder Con Cita
  #7  
Antiguo 08-03-2008
Ziara Ziara is offline
Miembro
 
Registrado: dic 2007
Posts: 43
Poder: 0
Ziara Va por buen camino
Hola, creo que ya está solucionado!

he estado ejecutando con puntos de ruptura y paso a paso.

puse un punto en la linea

void __fastcall TForm1::Button4Click(TObject *Sender)

y al darle al botón no se me paraba el código.. lo cual me hizo dudar... por tanto he creado un nuevo botón con el mismo contenido (para parar el thread) y ahora si que me para!!

Vamos.. que el código estaba bien planteado, lo que ocurre es que al darle al botón no me referenciaba al código y creo que es que cuando estuve haciendo pruebas, y tuve que comentar (poner las //), del builder me salió una ventanita diciéndome que no existía tal objeto o algo así (no estoy segura) y le día a aceptar y creo que con ello abría eliminado la relación del botón con el código.. o algo así .

muchas gracias de ahora en adelante tengo que usar más los puntos de ruptura.

Aún así tengo otra dudilla, con el watch, se puede ver los valores de las variables en tiempo de ejecución, lo he estado probando añadiéndo diferentes variables, pero al querer ver los valores me pone: [process not accesible]??
Responder Con Cita
  #8  
Antiguo 08-03-2008
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Enhorabuena.

Claro... No puedes ver las variables con el watch hasta que tu código no se está ejecutando en el ámbito de esas variables....

Saludos.

Última edición por escafandra fecha: 08-03-2008 a las 23:37:42.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Conexión con BD Access que tenga contraseña LinaC Tablas planas 2 01-02-2008 23:02:40
Ayuda, Problema con Application.terminate delphi .net nethcy .NET 2 08-05-2006 05:00:54
Thread bendito thread...se me pierde la ventana Seba.F1 API de Windows 5 02-02-2006 00:16:30
Application.Terminate Esau Varios 7 06-05-2005 14:12:36
Application.Terminate Vs Close neon Varios 2 30-07-2004 00:11:55


La franja horaria es GMT +2. Ahora son las 10:44:21.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi