Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   InterlockedExchange en 64 bits (https://www.clubdelphi.com/foros/showthread.php?t=89851)

xangiesaurx 18-02-2016 02:01:45

InterlockedExchange en 64 bits
 
Hola a todos, ya vengo a molestarlos de nuevo, ahora tengo una gran duda, estoy migrando un proyecto de Delphi 2010 a Delphi XE5 (Win64), en el que tengo esta línea de código
Código:

Thread := InterlockedExchange(Integer(FThread), 0);
Pero al parecer el InterlockedExchange no se puede importar a Delphi XE5, alguien sabe de que manera puedo usarlo para que funcione en 64bits?
Gracias :)

AgustinOrtu 18-02-2016 02:44:39

Conozco dos "InterlockedExchange"

Una de ellas esta definida en la unidad Windows.Winapi, y es una funcion que depende de una biblioteca externa; si vemos la declaracion:

Código Delphi [-]
function InterlockedExchange; external kernel32 name 'InterlockedExchange';

Por otro lado, la RTL de Delphi incluye una unidad, la System.SyncObjs en donde se define una clase
estatica que implementa la misma funcionalidad pero usando codigo Delphi; es decir, sin dependencias. De hecho, alguna de las funciones son implementadas "dentro del compilador", en lo que comunmente se le llama "magia" o en ingles "compiler magic", o el termino mas tecnico Intrinsic Routines

La clase en cuestion es la TInerlocked

La misma dispone de la funcion estatica Exchange que me imagino que servira para cualquiera de las plataformas que soporta Delphi

Saludos

Al González 18-02-2016 07:33:31

Toma muy en cuenta la respuesta de AgustinOrtu. :) ^\||/

Una pregunta: ¿de qué tipo es FThread?

En caso de ser puntero (u objeto), ten presente que una expresión como Integer(FThread), sólo considerará los cuatro bytes más bajos, ya que Integer es un tipo de dato de 32 bits (aun en plataformas de 64 bits), mientras que un puntero ocupa ocho bytes en sistemas operativos de 64 bits. Es decir, los punteros (los cuales abarcan a las variables objeto también) contienen un valor de 32 o de 64 bits, dependiendo de la plataforma para la que se haya compilado la aplicación.

Un saludo.

Al González.

xangiesaurx 18-02-2016 18:42:38

Muchas gracias por su ayuda, lo eh intentado y me sigue marcando este error:
"[dcc64 Error] BaseClass.pas(9911): E2197 Constant object cannot be passed as var parameter"

Y el código lo eh dejado de la siguiente manera en lo que encuentro como hacerlo funcionar:
Código:

procedure TBCAMThread.Close;
var
  Thread: THandle;
begin
  {$IFDEF WIN32}
    Thread := InterlockedExchange(Integer(FThread), 0);
  {$ELSE}
  {$IFDEF WIN64}


  {$ENDIF}
  {$ENDIF}
  if BOOL(Thread) then
  begin
    WaitForSingleObject(Thread, INFINITE);
    CloseHandle(Thread);
  end;
end;


AgustinOrtu 18-02-2016 20:47:52

El problema es que estas usando la funcion incorrectamente

Si vemos la firma de la funcion, tenemos:

Código Delphi [-]
class function Exchange(var Target: Pointer; Value: Pointer): Pointer; overload; static; inline;
class function Exchange(var Target: Integer; Value: Integer): Integer; overload; static; inline;
class function Exchange(var Target: Int64; Value: Int64): Int64; overload; static; inline;
class function Exchange(var Target: TObject; Value: TObject): TObject; overload; static; inline;
class function Exchange(var Target: Double; Value: Double): Double; overload; static; inline;
class function Exchange(var Target: Single; Value: Single): Single; overload; static; inline;
class function Exchangeclass>(var Target: T; Value: T): T; overload; static; inline;

Es importante notar que el primer parametro esta pasado por referencia, de ahi el modificador var

Quiere decir que no se puede enviar por parametro una expresion constante

Un ejemplo de uso correcto de la funcion TInterlocked.Exchange podria ser:

Código Delphi [-]
uses
  System.SyncObjs;

procedure TForm1.Button1Click(Sender: TObject);
var
  A, B, C: Integer;
begin
  A := 1;
  B := 2;
  C := TInterlocked.Exchange(A, B);

  ShowMessageFmt('A = %d, B = %d, C = %d', [A, B, C]);
end;

En donde el cuadro de dialogo imprime el mensaje:

A = 2, B = 1, C = 1

Lo cual es correcto, ya que si revisamos la implementacion de TInerlocked.Exchange, simplemente invoca a otra rutina del compilador, la AtomicExchange, donde la documentación explica:

Cita:

Writes the given value to the target and returns the previous value of the target.
--

Por otro lado tené muy en cuenta lo que comento Al Gonzalez; para responder con precision deberiamos saber el tipo de FThread

Si bien Delphi hace bastante sencilla la transicion de 32 a 64 bits, hay algunos puntos para revisar:

Revisa esta entrada

xangiesaurx 19-02-2016 02:23:00

AgustinOrtu, gracias por tu ayuda, parece que ya quedo solucionado, el código quedo de la siguiente manera
Código:

                {$IFDEF WIN32}
                            Thread := InterlockedExchange(Integer(FThread), 0);
                  {$ELSE}
                  {$IFDEF WIN64}
                            Thread := TInterlocked.Exchange(Int64(FThread), 0);
                  {$ENDIF}
                  {$ENDIF}

Lo hice de esta manera ya que me pidieron que tuviera el conditional compilation

AgustinOrtu 19-02-2016 02:30:08

Sólo una cosa más para puntualizar

Se recomienda el uso del tipo NativeInt para los casos en los que, como este, hay que lidiar con el diferente tamaño de los punteros

El tipo NativeInt, esta definido como un entero de 32 bits para el compilador de 32 bits, y como entero de 64 bits para el compilador de 64 bits

Es una manera de escribir código compatible a través de todas las plataformas, asegurando compatibilidad hacia adelante y atrás

xangiesaurx 20-02-2016 00:39:11

Si, muchas gracias, se me había pasado lo del NativeInt :P Pero ya esta implementado :)

Ahora tengo otra duda (ya se que soy algo latosa en esto), pero me acabo de encontrar parte de código ensamblador, pero a lo que eh leido, ya no es compatible con XE5, existe alguna forma de lograr esta compatibilidad?
(Aquí dejo el código en cuestion)

Código Delphi [-]
function FastCpySSE(const D:Pointer; const S:Pointer; const count:dword):integer;
var dwNumElements, dwNumPacks:DWORD;
begin
 dwNumElements := count div sizeof(integer);
 // not really using it, just for debuging. it keeps number of looping.
 // it also means number of packed data.
 dwNumPacks := dwNumElements div (128 div (sizeof(integer)*8));

 asm
  // remember for cleanup
  pusha;
@@begin:
  // init counter to SizeInBytes
  mov  ecx,count
  // get destination pointer
  mov  edi,D
  // get source pointer
  mov  esi,S
@@begina:
  // check if counter is 0, yes end loop.
  cmp  ecx,0
  jz  @@end
@@body:
  // calculate offset
  mov  ebx,count
  sub  ebx,ecx
  // copy source's content to 128 bits registers
  movdqa xmm1,[esi+ebx]
  // copy 128 bits registers to destination
  movdqa [edi+ebx],xmm1;

@@bodya:
  // we've done "1 packed == 4 * sizeof(int)" already.
  sub  ecx,16;
  jmp  @@begina
@@end:
  // cleanup
  popa;
end;

 result := 0;;
end;
Gracias por toda su ayuda y de nuevo una disculpa por las molestias

AgustinOrtu 20-02-2016 01:15:06

xangiesaurx

Realmente no domino ASM, pero de todos modos deberías iniciar una consulta nueva y no mezclar en un mismo hilo varias preguntas; asi lo dice la guía de estilo

xangiesaurx 20-02-2016 01:17:34

De acuerdo, entonces este tema se puede dar por cerrado.
Abriré uno nuevo con referencia a ASM y XE5, muchas gracias por toda la ayuda :)


La franja horaria es GMT +2. Ahora son las 03:55:02.

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