2014-01-28 7 views
2

При создании объекта потока я хочу вызвать код из приложения, которое необходимо синхронизировать. Проблема в том, что я не знаю, как вызвать Synchronize для функции приложения с параметрами.Параметры передачи для синхронизации вызова процедуры

Скажем, у нас есть

procedure ThreadObject.Execute; 
var 
    val1,val2:integer; 
    Star:string; 
begin 
    Synchronize(funcyfunc); //how to pass val1,val2,star here? 
end; 

где funcyfunc определяется как следовать

procedure OtherClass.funcyfunc(param1,param2:integer;spok:string); 
begin 
    letsCallFriends(spok,param1); 
    letsCallFriends(spok,param2); 
end; 

теперь странным решением этой проблемы было бы сказать в ThreadObject частной

и в осуществление делаем

procedure ThreadObject.starVal; 
begin 
    funcyfunc(Star,val1,val2); 
end; 

и в потоке выполнение перехода к

procedure ThreadObject.Execute; 
var 
    val1,val2:integer; 
    Star:string; 
begin 
    Synchronize(starVal); //how to pass val1,val2,star here? 
end; 

но это хлопоты, так как для каждого вызова процедуры должна быть глобальной переменной. Есть ли способ лучше?

код:

unit ThreadObject; 

interface 

uses 
    Classes; 

type 
    TThreadObject= class(TThread) 
    private 
    star:string; 
    val1,val2:integer; 
    procedure starVal; 
    protected 
    procedure Execute; override; 

    //assume we have a constructor that ini the star val1 val2. 
    end; 

implementation 

{ TThreadObject } 

procedure ThreadObject.Execute; 
var 
    val1,val2:integer; 
    Star:string; 
begin 
    Synchronize(starVal); //how to pass val1,val2,star here? 
end; 

procedure ThreadObject.starVal; 
begin 
    funcyfunc(Star,val1,val2); 
end; 

end. 
+2

['This way'] (http://pastebin.com/WD2LYNE5). – TLama

+3

Существует замечательная статья в блоге, посвященная этому http://www.uweraabe.de/Blog/2011/01/30/synchronize-and-queue-with-parameters/ –

+0

Возможный дубликат [Передача значения для синхронизации потока] (http://stackoverflow.com/questions/16870387/passing-value-to-synchronize-thread) – CinCout

ответ

7

Используйте анонимные методы.

Как вы можете прочитать в руководстве по TThread.Synchronize

Synchronize(
    procedure 
    begin 
    Form1.Memo1.Lines.Add('Begin Execution'); 
    end); 

В приведенном выше примере ссылается переменнаяForm1 бы вроде быть скопированы и сохранены, пока процедура не запускается на выполнение (что называется переменной захват).

Примечание: Дэвид возражает против идеи «скопированной переменной», и он, вероятно, прав. Однако обсуждение всех угловых дел и деталей реализации будет излишним. Его сравнение с «глобальной переменной» OTOH, вероятно, будет иметь проблемы с рекурсивными процедурами и т. Д. Все простые для понимания аналогии очень грубые и наклонены так или иначе ISTM.

Вашей анонимная процедура должна использовать переменные val1 и val2 и затем они должны получить захватили слишком

http://docwiki.embarcadero.com/Libraries/XE5/en/System.Classes.TThread.Synchronize

+3

FWIW, переменная не копируется ** **. Это ** захвачено **. Если у вас есть другой метод anon, который захватывает одну и ту же переменную, то оба метода anon относятся к ** той же ** переменной. Изменения, внесенные в этот var одним методом anon, видны в другом методе anon. Таким образом, захваченная переменная преобразуется из локальной в глобальную. –

+0

@DavidHeffernan, и если локальная процедура сама меняет значения между созданием двух методов anon? –

+3

Все три стороны, процедура, объявленная местными жителями, и два метода anon относятся к одной и той же переменной. Фактически переменная больше не находится в стеке, потому что, конечно, объем методов anon может пережить то, что было объявлено переменной. Захваченная переменная поднимается в объект, который находится на куче. –

2

Если вы используете старую версию Delphi, которая не поддерживает анонимные методы, вам создайте поля «параметры» в своем классе. То есть

procedure ThreadObject.Execute; 
var 
    val1,val2:integer; 
    Star:string; 
begin 
    FVal1 := val1; 
    FVal2 := val2; 
    FStar := Star; 
    Synchronize(funcyfunc); 
end; 

procedure ThreadObject.FuncyFunc; 
begin 
    //Do stuff with FVal1, FVal2 and FStar 
end; 

Примечание это не глобальные.
Это также вполне безопасно, потому что точка Synchronize предназначена для обеспечения согласования двух потоков друг с другом. Итак, если у вас нет других потоков, пытающихся получить доступ к тем же данным, у вас не будет условий гонки.

Да, это немного «klunky», но это преимущество использования анонимных методов в новых версиях Delphi.

 Смежные вопросы

  • Нет связанных вопросов^_^