2011-01-25 10 views
5

Ahora tengo una aplicación casi completa y la siguiente característica que quiero implementar es el enhebrado. Elegí ir con BeginThread(), aunque estoy al tanto de TThread en Delphi. El problema con el que me estoy cruzando es la estructura de la llamada BeginThread(). Normalmente, la línea en el programa que llamaría a la función que quiero enhebrar esBeginThread Structure - Delphi

CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op); 

op es un número entero.

La línea he cambiado hacia fuera para crear un hilo de ella es

BeginThread(nil,0,CompareFiles,Addr('form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op'),0,x); 

Desde la pequeña cantidad de infromation que puedo encontrar en la forma de utilizar realmente BeginThread() esto debe ser una multa de llamadas , sin embargo, al compilar, todo lo que obtengo son errores de compilador con respecto a la estructura de mis parámetros de enunciados BeginThread().

EDITAR PARA OBTENER INFORMACIÓN.

El procedimiento actual que llama CompareFiles es

procedure TForm1.Panel29Click(Sender: TObject); 
var 
op,x : integer; 

begin 
    if (Form1.Edit3.Text <> '') AND (Form1.Edit4.Text <> '') then 
     begin 
      op := 3; 
      if RadioButton7.Checked = True then op := 0; 
      if RadioButton3.Checked = True then op := 1; 
      if RadioButton4.Checked = True then op := 2; 
      if RadioButton5.Checked = True then op := 3; 
      if RadioButton6.Checked = True then op := 4; 
      CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op); 
     end; 
end; 

Si tuviera que utilizar TThread según lo sugerido por un par de personas, y como se muestra a continuación por Rob, estoy confundido cómo a) me lo pase op, Edit3/4.Text y StringGrid2 a CompareFiles. Adivinando el ejemplo de TThread que he visto pensé que iba a reemplazar el código anterior con el TCompareFilesThread.Execute y poner el código actual de Panel29Click en TCompareFilesThread.Create y luego añadir

FEdit3Text := Edit3Text; 
FEdit4Text := Edit4Text; 
FGrid := Grid; 

a este

FEdit3Text := Form1.Edit3.Text; 
FEdit4Text := Form1.Edit4.Text; 
FGrid := Form1.StringGrid2; 

Pero Tengo esta sensación molesta que está totalmente fuera de lugar.

+0

"Quejas sobre cosas que no coinciden" no es una descripción muy útil. ¿Podría editar su pregunta y pegar una copia del mensaje de error en por favor? –

+2

También me pregunto por qué elige * no * usar TThread? El uso de funciones de subprocesos globales sin una buena encapsulación de objetos complica enormemente las cosas relacionadas con la concurrencia y las condiciones de carrera. También me llama la atención por qué está a punto de completar la aplicación y luego decidí agregarla. OMI, el enhebrado debe considerarse desde el principio y no en el último momento. Existe una alta probabilidad de enhebrar minas terrestres si no se toman en cuenta con suficiente antelación. –

+0

El motivo por el que se está implementando el enhebrado ahora es que esta es una aplicación de aprendizaje para mí. El enhebrado siempre fue planeado solo para implementarlo ahora que las características principales de las aplicaciones están completas (en su mayoría). En cuanto a TThread, no puedo encontrar una buena explicación sobre cómo usarlo. – jskrwyk

Respuesta

14

Eso no es en absoluto la manera de usar BeginThread. Esa función espera un puntero a una función que toma un parámetro, pero la función a la que intenta llamar necesita cuatro. El único parámetro que le está dando a BeginThread para reenviar al procedimiento de subproceso es una cadena, pero evidentemente espera que algún tipo de magia convierta esa cadena de caracteres en los valores que contienen esas variables.

así no es como funciona Delphi, e incluso para los idiomas que pueden hacer algo por el estilo, generalmente se desalienta a hacer realidad ella.

pasar varios parámetros a BeginThread, definen un registro con todos los valores que necesita, y también definir un puntero de registro:

type 
    PCompareFilesParams = ^TCompareFilesParams; 
    TCompareFilesParams = record 
    Edit3Text, 
    Edit4Text: string; 
    Grid: TStringGrid; 
    Op: Integer; 
    end; 

Cambio CompareFiles a aceptar un puntero a ese registro:

function CompareFiles(Params: PCompareFilesParams): Integer; 

para iniciar el hilo, tendrá que asignar una instancia de ese registro y poblar sus campos:

var 
    Params: PCompareFilesParams; 
begin 
    New(Params); 
    Params.Edit3Text := Edit3.Text; 
    Params.Edit4Text := Edit4.Text; 
    Params.Grid := StringGrid2; 
    Params.Op := op; 
    BeginThread(nil, 0, @CompareFiles, Params, 0, x); 

Implementar CompareFiles como éste, así que el registro va a obtener liberados antes de que termine el hilo:

function CompareFiles(Params: PCompareFilesParams): Integer; 
begin 
    try 
    // <Normal implementation goes here.> 
    finally 
    Dispose(Params); 
    end; 
end; 

Puede hacer que todo sea mucho más fácil si usted sólo tiene que utilizar TThread, sin embargo. Puedes hacer que tu clase descendiente tenga tantos parámetros como quieras en su constructor, para que no tengas que perder el tiempo asignando dinámicamente y liberando un registro especial.

type 
    TCompareFilesThread = class(TThread) 
    private 
    FEdit3Text, 
    FEdit4Text: string; 
    FGrid: TStringGrid; 
    FOp: Integer; 
    procedure Execute; override; 
    public 
    constructor Create(const Edit3Text, Edit4Text: string; Grid: TStringGrid; Op: Integer); 
    property ReturnValue; 
    end; 

constructor TCompareFilesThread.Create; 
begin 
    inherited Create(False); 
    FEdit3Text := Edit3Text; 
    FEdit4Text := Edit4Text; 
    FGrid := Grid; 
    FOp := Op; 
end; 

procedure TCompareFilesThread.Execute; 
begin 
    ReturnValue := CompareFiles(FEdit3Text, FEdit4Text, FGrid, FOp); 
end; 

En lugar de llamar BeginThread, sólo una instancia de la clase y se deja correr:

var 
    ThreadRef: TThread; 


ThreadRef := TCompareFilesThread.Create(Edit3.Text, Edit4.Text, StringGrid2, Op); 

Hay más a la utilización de hilos, como saber cuando el mensaje ha terminado de ejecutarse, pero yo creo que hay lo suficiente para comenzar. Una última cosa a tener en cuenta, sin embargo, es que TStringGrid es un control de VCL. No debe hacer nada con este nuevo hilo que cree (independientemente de cómo termine creándolo). Todo lo que haga con el control de la red debe hacerse desde el hilo principal. Use TThread.Synchronize y TThread.Queue para cambiar cualquier operación de VCL al hilo principal. El subproceso de comparación de archivos esperará a que se complete la operación sincronizada, pero seguirá ejecutándose sin esperar a que se complete una operación en cola.

+0

+1 para la gran explicación! pero "Eliminar (Params);" debería ser "Dispose (Params);" – arthurprs

+0

@Arthurprs ¡Vaya! ¿Puedes decir que uso C++ todo el día? –

+0

Si puedo descubrir cómo usar TThread, lo haré. Por ejemplo, con el código de ejemplo que tiene allí, qué/cómo lo llamaría en el procedimiento OnClick, que establece op y decide cuándo ejecutar los CompareFiles. – jskrwyk