Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Desarrollo en Delphi para Android
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy


Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 08-10-2023
jhonalone jhonalone is offline
Miembro
 
Registrado: sep 2007
Ubicación: Madrid
Posts: 547
Poder: 17
jhonalone Va por buen camino
¿Se pueden modificar Global Vars en un TThread?

Hola, de nuevo, amigos del foro.
Nunca había usado hilos en mis aplicaciones. Quizá no fuera necesario.
Después de este problema y gracias a dani36652 que me ayudó a resolverlo con un hilo, he visto la utilidad de los mismos.
Como digo en el enunciado, me veo en la necesidad de modificar alguna variable que no está declarada en el hilo.
Tengo el problema de que no se actualiza al terminar el hilo.
Al insistir una o dos veces más termina tomando su correcto valor. Pero esto no es operativo.
Se trata de comprobar si una impresora conectada por BlueTooth está operativa o no.
Os participo el código que estoy utilizando, por si alguien puede ayudarme.
(Conste que antes de solicictar vuestra ayuda llevo 2 dias buscando en internet sin éxito)

Código Delphi [-]
-----------------------------------------------------------------
    procedure ImpresoraConectada;
    procedure ImpresoraLista;

     { Private declarations }
  private
      Impresora : TBluetoothDevice;
      FSocket: TBluetoothSocket;
      BluetoothAdapter: TBluetoothAdapter;
      FBluetoothManager : TBluetoothManager;
      ServiceGUI : String;
      Guid :  TGUID;
      ServiceName : String;
      ResultadoImpresora : Boolean;// Lleva el resultado de ImpresoraConectada


  public
    { Public declarations }
end;

var
  Presu: TPresu;

implementation
----------------------------------------------------------------------
procedure TPresu.ImpresoraLista;
var
 Thread: TThread;
begin

 Thread:= TThread.CreateAnonymousThread(
    procedure
    begin
     TThread.ForceQueue(TThread.CurrentThread,
     ImpresoraConectada) // Activamos el procedimiento lento en el Thread
    end);

   Thread.FreeOnTerminate:= True;
   Thread.Start;

end;

procedure TPresu.ImpresoraConectada;
var
  Msg: string;
  I, B: Integer;

  ListaVinculados: TBluetoothDeviceList;
  LServices: TBluetoothServiceList;

begin
ResultadoImpresora := False; // ES LA VARIABLE GLOBAL DE LA TFORM
                             // QUE NO SE MODIFICA DESPUES DE TERMINAR
                             // EL TTHREAD
                             // SI REPITES EL TTHREAD TERMINA CAMMBIANDO

  try
    FBluetoothManager := TBluetoothManager.Current;
    if FBluetoothManager = nil
    then begin
         Mensaje(Form1.NoCodi(ST.Strings[79]), 0);
         Exit;
         end;

    FBluetoothManager.SocketTimeout := 100;

    BluetoothAdapter := FBluetoothManager.CurrentAdapter;
    if BluetoothAdapter = nil
    then begin
         Mensaje(Form1.NoCodi(ST.Strings[80]), 0);
         Exit;
         end;

    ListaVinculados := FBluetoothManager.GetPairedDevices(BluetoothAdapter);
    if ListaVinculados = nil
    then begin
         Mensaje(Form1.NoCodi(ST.Strings[81]), 0);
         Exit;
         end;

      // DeviceElegido es la posición de la impresora en ListaVinculados
      Impresora := ListaVinculados[DeviceElegido] as TBluetoothDevice;
      if Impresora.IsPaired then
      begin
        LServices := Impresora.GetServices;
        for B := 0 to LServices.Count - 1 do
        begin
          ServiceGUI := GUIDToString(LServices[b].UUID);
          Guid := LServices[b].UUID;
          ServiceName := LServices[b].Name;
        end;
      end
      else begin
           Mensaje(Form1.NoCodi(ST.Strings[82]), 0);
           Exit;
           end;

  except
   on E: Exception do
   begin
     Msg := E.Message;
     Mensaje('Error al Conectar el Software de la Impresora: ' + Msg, 0);
     Exit;
   end;
 end;

    try
    FSocket := Impresora.CreateClientSocket(Guid, true);

    if (Assigned(Impresora)) And (Assigned(FSocket))
    then Begin
         FSocket.Connect; // Sólo para comprobación
         FSocket.Close; // Sin Esto da error al imprimir ES MUY IMPORTANTE CERRAR SOCKET AUNQUE SE ABRA DE NUEVO AL USARLO
                    // java.io.IOException: read failed, socket might closed or time out, read ret:-1
         ResultadoImpresora := True;
         End;

    except
      on E: Exception do
      begin
          ResultadoImpresora := False; // No es necesario, pero es mas legible
          Exit;
      end;
    end;

end;
-------------------------------------------------------------------
ImpresoraLista;

                if not ResultadoImpresora  // E
                then begin 
                       // Mesaje de error en la impresora
                     end
                else begin
                    // Aquí va el módulo de impresion gestionado por el mensaje de confirmación
                     end;

Esperando que, si el problema tiene solución y alguien lo sabe, la comparta conmigo.
Gracias de antemano.
Saludos cordiales.
__________________
"Pedid y se os dará; buscad y hallaréis ..." (Lc 11,9-10)
"...si no tengo caridad, nada soy..." (1 Cor 13,1-13)

Última edición por jhonalone fecha: 08-10-2023 a las 16:31:11.
Responder Con Cita
  #2  
Antiguo 08-10-2023
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.040
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
A falta de que lo confirme alguien más experto, pienso que sí es posible.
Código Delphi [-]
unit MainUnit;

interface

var
  GlobalVariable: Integer;

implementation

// Resto de tu código...

end.
Código Delphi [-]
unit MyThreadUnit;

interface

uses
  System.Classes;

type
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;

implementation

procedure TMyThread.Execute;
begin
  // Modificar la variable global
  GlobalVariable := 42;
end;
end.
Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  MyThread: TMyThread;
begin
  // Crear e iniciar el hilo
  MyThread := TMyThread.Create(True);
  MyThread.Start;

  // Esperar a que el hilo termine (opcional)
  MyThread.WaitFor;

  // Liberar la memoria del hilo
  MyThread.Free;

  // Ahora puedes acceder a GlobalVariable modificada por el hilo
  ShowMessage('Valor de GlobalVariable: ' + IntToStr(GlobalVariable));
end;
Responder Con Cita
  #3  
Antiguo 08-10-2023
jhonalone jhonalone is offline
Miembro
 
Registrado: sep 2007
Ubicación: Madrid
Posts: 547
Poder: 17
jhonalone Va por buen camino
Muchas gracias Casimiro.
Es probable que, el código que has hecho el esfuerzo de confeccionar para aydarme, funcione.
No lo he probado.
Pero yo necesito cambiar el valor de la variable en el procedure "ImpresoraConectada". Claro, dependiendo del resultado de la comprobación que se hace en dicho procedimiento. ESte procedimiento dentro de "TThread.ForceQueue" (o en su lugar de "TThread.Synchronize" que fue lo primero que probé)
Un Sincero saludo.
__________________
"Pedid y se os dará; buscad y hallaréis ..." (Lc 11,9-10)
"...si no tengo caridad, nada soy..." (1 Cor 13,1-13)
Responder Con Cita
  #4  
Antiguo 08-10-2023
jhonalone jhonalone is offline
Miembro
 
Registrado: sep 2007
Ubicación: Madrid
Posts: 547
Poder: 17
jhonalone Va por buen camino
Hola.
Este comportamiento de que no pasa el valor inmediatamente y que lo pasa después en diferido, en la siguiente llamada, me recuerda el comportamiento asincrónico de JavaScript.
Allí tenemos la función CallBack para evitarlo. (Si no recuerdo mal)
¿Hay algo parecido aquí?
Saludos.
__________________
"Pedid y se os dará; buscad y hallaréis ..." (Lc 11,9-10)
"...si no tengo caridad, nada soy..." (1 Cor 13,1-13)
Responder Con Cita
  #5  
Antiguo 09-10-2023
dani36652 dani36652 is offline
Miembro
 
Registrado: abr 2019
Posts: 55
Poder: 6
dani36652 Va camino a la fama
Hola, claro que si se puede. Solo que si dicha variable es utilizada por otros hilos más, te recomiendo meter esa asignación en un "Synchronize" todo esto para evitar errores de acceso de memoria o errores de acceso múltiple.

Revisando tu código, hice algunas correcciones y te hago de forma constructiva las siguientes observaciones.
  • Los cambios dados a componentes visuales dentro de otros hilos que no sean el hilo principal, deben ir dentro de un Synchronize.
  • Los mensajes, cuadros de diálogo y cambios en variables globales, de igual forma van dentro de un Synchronize.

Observé también que mostrabas mensajes y después hacias un exit; puedo intuir que no apreciabas el cambio del valor de la variable por que en algún punto tu app caía en las líneas que mostraban mensajes pero como no sincronizabas con el hilo principal, no se veía nada y no cambiaba la variable por el exit antes mencionado.

Te dejo más o menos cómo quedaría tu código y como comentario final, no olvides que la impresión tanto en Android como en Windows siempre debe llamarse en el Hilo principal.
Si haces eso desde otro hilo aplica algo como esto para que se ejecute en el hilo principal
Código Delphi [-]
TThread.Synchronize(nil,
procedure
begin
  Imprimir;
end);

//Tu código

Código Delphi [-]
(*-----------------------------------------------------------------*)
procedure ImpresoraConectada;
procedure ImpresoraLista;

{ Private declarations }
private
  Impresora : TBluetoothDevice;
  FSocket: TBluetoothSocket;
  BluetoothAdapter: TBluetoothAdapter;
  FBluetoothManager : TBluetoothManager;
  ServiceGUI : String;
  Guid :  TGUID;
  ServiceName : String;
  ResultadoImpresora : Boolean;// Lleva el resultado de ImpresoraConectada
{ Public declarations }
public
end;

var
  Presu: TPresu;

implementation
(*----------------------------------------------------------------------*)
procedure TPresu.ImpresoraLista;
var
 Thread: TThread;
begin
  (*
  TThread.ForceQueue(TThread.CurrentThread,
  ImpresoraConectada)
  Esto no es correcto, ya que estás poniendo en cola la llamada al método y por ende
  no se actualiza el valor de la variable cuando es esperado.*)
  Thread:= TThread.CreateAnonymousThread(
  procedure
  begin
    ImpresoraConectada;
  end);

  Thread.FreeOnTerminate:= True;
  Thread.Start;
end;

procedure TPresu.ImpresoraConectada;
var
  Msg: string;
  I, B: Integer;

  ListaVinculados: TBluetoothDeviceList;
  LServices: TBluetoothServiceList;
begin
  (*ES LA VARIABLE GLOBAL DE LA TFORM QUE NO SE MODIFICA DESPUES DE TERMINAR EL TTHREAD
  SI REPITES EL TTHREAD TERMINA CAMMBIANDO*)
  TThread.Synchronize(TThread.CurrentThread,
  procedure
  begin
    ResultadoImpresora := False;
  end);

  try
    FBluetoothManager := TBluetoothManager.Current;
    if not Assigned(FBluetoothManager) then
    begin
      TThread.Synchronize(TThread.CurrentThread,
      procedure
      begin
        Mensaje(Form1.NoCodi(ST.Strings[79]), 0);
      end;
      Exit;
    end;

    FBluetoothManager.SocketTimeout := 100;

    BluetoothAdapter := FBluetoothManager.CurrentAdapter;
    if not Assigned(BluetoothAdapter) then
    begin
      TThread.Synchronize(TThread.CurrentThread,
      procedure
      begin
        Mensaje(Form1.NoCodi(ST.Strings[80]), 0);
      end);
      Exit;
    end;

    ListaVinculados := FBluetoothManager.GetPairedDevices(BluetoothAdapter);
    if not Assigned(ListaVinculados) then
    begin
      TThread.Synchronize(TThread.CurrentThread,
      procedure
      begin
        Mensaje(Form1.NoCodi(ST.Strings[81]), 0);
      end);
      Exit;
    end;

    // DeviceElegido es la posición de la impresora en ListaVinculados
    Impresora := ListaVinculados[DeviceElegido] as TBluetoothDevice;
    if Impresora.IsPaired then
    begin
      LServices := Impresora.GetServices;
      for B := 0 to LServices.Count - 1 do
      begin
        ServiceGUI := GUIDToString(LServices[b].UUID);
        Guid := LServices[b].UUID;
        ServiceName := LServices[b].Name;
      end;
    end
    else
    begin
      TThread.Synchronize(TThread.CurrentThread,
      procedure
      begin
        Mensaje(Form1.NoCodi(ST.Strings[82]), 0);
      end;
      Exit;
    end;

  except
    on E: Exception do
    begin
      Msg := E.Message;
      (*Recuerda que todo lo visual y referente a la interfaz de usuario
      (cuadros de diálogo, texto de labels, botones, etc.) así como
      variables globales que puedan ser modificadas por otros hilos, deberán meterse
      en un Syncrhonize*)
      TThread.Synchronize(TThread.CurrentThread,
      procedure
      begin
        Mensaje('Error al Conectar el Software de la Impresora: ' + Msg, 0);
      end);
      Exit;
    end;
  end;

  try
    FSocket := Impresora.CreateClientSocket(Guid, true);
    if (Assigned(Impresora)) And (Assigned(FSocket)) then
    Begin
      (*
      1.- Conectas el socket
      2.- Asignas valor a la variable
      3.- Cierras el socket
      *)
      FSocket.Connect; // Sólo para comprobación
      TThread.Synchronize(TThread.CurrentThread,
      procedure
      begin
        (*Te recomiendo efectuar los cambios de valores a una variable global
        desde otros hilos con un Synchronize*)
        ResultadoImpresora := True;
      end);
      FSocket.Close; // Sin Esto da error al imprimir ES MUY IMPORTANTE CERRAR SOCKET AUNQUE SE ABRA DE NUEVO AL USARLO
      // java.io.IOException: read failed, socket might closed or time out, read ret:-1
    End;

  except
    on E: Exception do
    begin
      TThread.Synchronize(TThread.CurrentThread,
      procedure 
      begin
         ResultadoImpresora := False; // No es necesario, pero es mas legible
      end);
      Exit;
    end;
  end;
end;
-------------------------------------------------------------------
ImpresoraLista;
if not ResultadoImpresora then  // E
begin
  // Mesaje de error en la impresora
end
else
begin
  // Aquí va el módulo de impresion gestionado por el mensaje de confirmación
end;

Última edición por dani36652 fecha: 09-10-2023 a las 20:46:37.
Responder Con Cita
  #6  
Antiguo 10-10-2023
jhonalone jhonalone is offline
Miembro
 
Registrado: sep 2007
Ubicación: Madrid
Posts: 547
Poder: 17
jhonalone Va por buen camino
Hola, Dani.
Agradezco infinito el esfuerzo que has hecho para corregir mi código.
Gracias a ti estoy empezando a conocer los hilos (TThread) que no había usado nunca.
Anoche he corregido mi código con tus modificaciones.
No te he respondido antes, porque estoy intentando ver cómo hacerlo funcionar.
Lo implementé con una ilusión tremenda y con una confianza total.
Pero al probarlo en el móvil y la impresora me da el mismo problema que antes.
Es decir el TThread no modifica instantáneamente el valor de la variable boleana "ResultadoImpresora", lo hace a la segunda vez (como lo hacía antes).
No me lo podía creer. He cambiado la variable boleana por otra variable visual, por una TLabel, y sigue el problema igual.
Este es el motivo de que no te haya responedido antes: he estado probando cómo conseguirlo.
Bueno, algo hemos conseguido: la respuesta es bastante más rápida.
Sigo probando... Si consigo algo lo comunicaré para que le aproveche a quien tenga el mismo problema.
Un Saludo muy cordial.
__________________
"Pedid y se os dará; buscad y hallaréis ..." (Lc 11,9-10)
"...si no tengo caridad, nada soy..." (1 Cor 13,1-13)

Última edición por jhonalone fecha: 10-10-2023 a las 15:55:08.
Responder Con Cita
  #7  
Antiguo 11-10-2023
jhonalone jhonalone is offline
Miembro
 
Registrado: sep 2007
Ubicación: Madrid
Posts: 547
Poder: 17
jhonalone Va por buen camino
¡¡SOLUCIONADO!!
Vaya por delante mi agradecimiento a dani36652 por haberme instruído en el manejo de los hilos.
Como prometí en mi post anterior, y como es mi costumbre, paso a relataros mis observaciones al respecto.

1.- La toma del valor asignado a una variable global es asincrónico si se quere utilizar fuera del TThread.
2.- Esto quiere decir que no se asigna el valor inmediatamente, la primera vez que se intenta.
3.- Cuando vuelves a reiniciar el hilo, asigna el valor de la primera vez. Y guarda el nuevo valor para la siguiente.
4.- Y así sucesivamente. El valor asignado va siempre con una llamada de retraso.
5.- Sin embargo, cuando estás dentro del hilo puedes usar el valor asignado correctamente.

La solución consistió en esto: utilizar la variable dentro del hilo para los propósittos que necesites.

Saludos muy cordiales.
__________________
"Pedid y se os dará; buscad y hallaréis ..." (Lc 11,9-10)
"...si no tengo caridad, nada soy..." (1 Cor 13,1-13)
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
Salir de TThread joseprad Varios 4 03-01-2015 16:43:36
FTP y TThread keys Internet 4 01-06-2011 08:12:43
TThread y componentes de red noob OOP 0 18-04-2009 01:25:07
File_get_contents & POST Vars Delar PHP 2 17-10-2007 17:15:31
Lio con TThread diegofhernando Varios 0 20-01-2004 17:58:35


La franja horaria es GMT +2. Ahora son las 16:52:57.


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