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 22-12-2015
mizzard mizzard is offline
Miembro
NULL
 
Registrado: feb 2011
Posts: 100
Poder: 14
mizzard Va por buen camino
abortar proceso y mostrar estado

Buenas tardes a todos!,

Os comento por encima lo que quiero realizar.

Estoy programando una aplicación en C++Builder XE3, la cual consulta una base de datos de Access (MDB) de clientes y con un boton mando publicidad personalizando el mail con archivos adjuntos a todos los clientes que cumplan con unos requisitos concretos (vamos una especie de SPAM automático).

El caso es que me funciona perfectamente tanto la conexión a mi BBDD, como la actualización y consulta de información y el envío de mails de forma automática. El problema que tengo es que (de momento estoy haciendo pruebas con una BBDD con pocos clientes ficticios para verificarlo) cuando le doy al botón enviar el programa se queda pensando hasta que manda todos los correos de golpe y no me actualiza las variables intermedias ni me deja la posibilidad de cancelar el envio tras terminar una transacción correcta (para evitar datos corruptos en la BBDD).

Para realizar el envio multiple hago una consulta a la BBDD con el filtrado deseado y acto seguido con un bucle for voy linea a linea enviando los mails y actualizando la BBDD hasta que termino de recorrer la tabla.

Dentro del bucle tengo el siguiente código:

Código:
			// PROCEDEMOS A SU ENVIO
			try{
				IdSMTP1->Connect();
				IdSMTP1->Send(Form1->IdMessage1);
				contadorEmailsEnviados++;


				DBConnectionBBDD->BeginTrans();
				try{
				// Actualizamos la ruta en la BBDD en la sección de configuración
				strSQL = "UPDATE ... (no es importante)
				cmdBBDD->CommandText = strSQL;
				cmdBBDD->Execute();

				DBConnectionBBDD->CommitTrans();
				}

				catch(Exception &exception){
					DBConnectionBBDD->RollbackTrans();
					Application->ShowException(&exception);
				}
			}
			catch(Exception &exception)
			{
				Application->ShowException(&exception);
				Label1->Caption = "¡Error!";
				break;
			}
			IdSMTP1->Disconnect();
			IdMessage1->Clear();

			Label1->Caption = contadorEmailsEnviados;
	//		Application->MessageBoxW(L"Todo ok, pasamos al siguiente.",L"Info",MB_OK+ MB_ICONERROR);
		} // Fin de condicion IF (no la he pegado)
	}// fin bucle for
En Label1 muestro el nº conforme se van enviando, pero por contra el programa se queda "atascado" hasta que envia todos y entonces ya me aparece el valor final.
Sin embargo si descomento la linea donde sale el MessageBox, en el momento de envio me sale ese mensaje (que no sirve para nada), pero sí que se actualiza la variable contadorEmailsEnviados en cada envio.

¿Se os ocurre alguna forma de poder mostrar en tiempo real cada vez que se envie un email e incluso con un boton poder abortar?
¿habría que iniciar otro proceso para evitar bloquear el programa y consultar el estado de una variable para finalizar todos los pasos intermedios y asi evitar corromper la BBDD?
¿Como se haria?

Muchas gracias de antemano y un abrazo!
Responder Con Cita
  #2  
Antiguo 22-12-2015
mizzard mizzard is offline
Miembro
NULL
 
Registrado: feb 2011
Posts: 100
Poder: 14
mizzard Va por buen camino
Hola de nuevo!

Parece que ya lo he resuelto, la solución se puede intuir en el siguiente hilo:

http://www.clubdelphi.com/foros/show...roceso+abortar

Al final lo he solucionado cambiando el bucle por un do...while, donde en el while se analiza un boolean (que lo cambio con el boton abortar), de esta forma e insertando Application->ProcessMessages(); parece que funciona bien.

No obstante seguiré haciendo pruebas.

Un abrazo!
Responder Con Cita
  #3  
Antiguo 23-12-2015
mizzard mizzard is offline
Miembro
NULL
 
Registrado: feb 2011
Posts: 100
Poder: 14
mizzard Va por buen camino
Retomo el tema

Buenas tardes de nuevo,

Retomo el hilo porque lo estoy planteando con threads y me estoy armando un lio.

Por casualidades me he dado cuenta que cuando mando el email:

Código:
Form1->IdSMTP1->Connect();
Form1->IdSMTP1->Send(Form1->IdMessage1);
Puede darse el caso de que el servidor tarde más de lo esperado, por lo que me propongo usar threads (nunca las he usado).

Basándome en el siguiente video:
https://www.youtube.com/watch?v=1g4db90Mfgw

Adapto mi código de tal forma que parece ser que funciona, pero tengo los siguientes problemas:

1º Antes llamaba a una función que se encargaba de gestionar los envíos, pasándole un parámetro para actuar de una forma u otra (aprovechando el codigo de envio)

Ahora al tener que insertar el codigo en la Unit2.cpp dentro de la sección de void __fastcall TConnectThread::Execute() he sacado el codigo de la funcion y no sé como hacerlo para que cuando se ejecute el thread que se active la funcion que tenia antes estilo:
Código:
void enviarEmail(int opcion);
Eso o actuar sobre variables globales, pero me da a mi que es mejor pasársela por función.

2º En el Unit1.cpp

Cuando deseo llamar al Thread, utilizo:
Código:
myThread1->Start();
Ya que tengo la siguiente linea:

Código:
TConnectThread *myThread1 = new TConnectThread(true);
Al principio del todo (inmediatamente despues de los includes, de los #pragma link, TForm1 *Form1)

No sé si es que lo estoy utilizando mal o que es lo que pasa, que mi objetivo es utilizar un timer programado con un tiempo para que si se queda enganchado el servidor de envio que aborte el thread de forma drástica.

En el timer pongo:
Código:
myThread1->Terminate();
Y dentro del thread en la condicion while añado && !Terminated, pero claro funciona cuando no se engancha en el servidor
Si pruebo con esto otro
Código:
	unsigned long exitCode;
	GetExitCodeThread(myThread1, &exitCode);
	TerminateThread(myThread1, exitCode);
Parando el timer posteriormente, indicar que el thread no para, ya que continua.


CONCLUSIÓN:

Me gustaria utilizar un thread para evitar cuelgues del programa cuando se envian varios emails y el servidor puede que se caiga, para ello necesito enviar variables al thread para aprovechar la funcion de envio que utilizaba y saber como abortar en caso de que me desborde el timer

¿Alguna orientación de como hacerlo?

Muchas gracias y un abrazo!
Responder Con Cita
  #4  
Antiguo 23-12-2015
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
No estoy seguro de que el ttimer sea thread safe.

Todo lo que sea externo al thread debe ser sincronizado para poder accederlo, consultarlo o modificarlo

Lo mejor es no usar variables globales, y los parámetros que sean copias. OJO no es un dogma, pero en muchos casos la sincronización termina siendo cuello de botella, es más práctico copiar el recurso y usarlo que compartirlo

En tu caso yo usaría un ttimer por thread, es decir, cada thread tiene su ttimer
Responder Con Cita
  #5  
Antiguo 23-12-2015
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
Cita:
Empezado por mizzard Ver Mensaje
En el timer pongo:
Código:
myThread1->Terminate();
Y dentro del thread en la condicion while añado && !Terminated, pero claro funciona cuando no se engancha en el servidor
Si pruebo con esto otro
Código:
    unsigned long exitCode;
    GetExitCodeThread(myThread1, &exitCode);
    TerminateThread(myThread1, exitCode);
Parando el timer posteriormente, indicar que el thread no para, ya que continua.
El método Terminate() No asegura que el thread termine, sólo que saldrá del bucle de Execute, si lo tiene. Si el hilo está "enganchado" por el servidor, no terminará de este modo. Quizás la respuesta esté en manipular IdSMTP. Si vas a usar varios hilos, sería lo suyo si envías varios emails, éstos no deberían depender de Form1->IdSMTP1, sino tener su propio componente.

El siguiente código con la API TerminateThread acaba con el hilo fulminantemente y debe usarse con myThread1->Handle. No es la forma recomendable de terminar un hilo, pues puedes tener fugas de memoria al no liberarse correctamente.
Código:
TerminateThread(myThread1, exitCode);
Código:
TerminateThread(myThread1->Handle, exitCode);
Saludos.
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
mostrar animación con mensaje durante un proceso vicens22 Desarrollo en Delphi para Android 5 15-05-2014 13:48:02
Mostrar en Progress Bar un proceso matti Varios 4 31-05-2011 14:55:01
Mostrar el estado del programa. mcalmanovici Varios 3 25-03-2008 20:02:18
Como abortar correctamente un proceso que es interrumpido por el cierre del Form gluglu Varios 10 28-08-2007 15:41:03
Abortar un proceso TONIAM Varios 10 31-05-2007 19:26:41


La franja horaria es GMT +2. Ahora son las 08:57:01.


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