2015-02-04 3 views
0

Использование: Delphi XE2, приложение Windows VCL FormsDelphi - Может ли TThread изменить значение переменной в основном потоке VCL?

Может ли TThread во время его выполнения изменять значение переменной в основном потоке VCL?

Необходимо обновить целое число, объявленное как поле класса TForm. Он будет передан TThread как переменная var в перегруженном (и повторно вводимом) методе Create constructor.

Есть ли какие-либо недостатки в этом?

+0

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

+0

Я также не уверен, что передача параметра var в конструктор потока позволит потоку обновлять эту переменную (кроме как внутри конструктора). Для этого вам понадобится указатель на это целое число, которое по-прежнему небезопасно, поскольку эта переменная является частью VCL. –

+0

Возможный дубликат [Thread-safe in delphi] (http://stackoverflow.com/questions/17705197/thread-safe-in-delphi) –

ответ

7

Да, потоки могут изменять переменные. Переменные не относятся к тем. Переменные могут принадлежать объектам формы или потока, но объект потока (т. Е. Экземпляр TThread или его потомки) отличается от потока выполнения ОС.

Объекты могут иметь код, который работает в нескольких потоках. Ваш метод TThread.Create работает в контексте потока, который его вызывает, что часто является вашим основным потоком. С другой стороны, метод Execute работает в контексте созданного потока ОС. Но очевидно, что оба метода могут получить доступ к полям объекта TThread, чтобы ответить на вопрос, могут ли две потоки ОС обращаться к одной и той же переменной.

У вас возникнут проблемы с доступом к переменной формы так, как вы ее описываете. Передача его конструктору в качестве параметра var позволит построить конструктор , но, как я уже упоминал выше, конструктор не запускается в контексте нового потока ОС. Чтобы позволить новому потоку получить доступ к этой переменной, вам нужно будет сохранить указатель на него вместо передачи по ссылке. Например:

type 
    TSteveThread = class(TThread) 
    private 
    FVariable: PInteger; 
    protected 
    procedure Execute; override; 
    public 
    constructor Create(Variable: PInteger); 
    end; 

constructor TSteveThread.Create; 
begin 
    inherited Create(False); 
    FVariable := Variable; 
end; 

procedure TSteveThread.Execute; 
begin 
    // Access FVariable^ here. 
end; 

Создать это следующим образом:

procedure TSteveForm.ButtonClick; 
begin 
    TSteveThread.Create(@Self.Variable); 
end; 

Альтернативы передать ссылку на форму вместо этого, а затем получить доступ поля формы через эту ссылку. Например:

type 
    TSteveThread = class(TThread) 
    private 
    FForm: TSteveForm; 
    protected 
    procedure Execute; override; 
    public 
    constructor Create(Form: TSteveForm); 
    end; 

constructor TSteveThread.Create; 
begin 
    inherited Create(False); 
    FForm := Form; 
end; 

procedure TSteveThread.Execute; 
begin 
    // Access FForm.Variable here. 
end; 

Создать это следующим образом:

procedure TSteveForm.ButtonClick; 
begin 
    TSteveThread.Create(Self); 
end; 

В любом случае, вы должны принять обычные меры предосторожности, о контроле одновременного доступа к данным нескольких потоков. Суть в том, что оба потока могут получить доступ к данным.

+0

Я был отброшен на секунду, так как в декларации 'Create' был параметр, но часть' Реализация' этого не делала. Тогда я вспомнил, хотя это запутанно, это действительно код. Чтобы избежать путаницы, я всегда делаю подпись «Реализация» идеально совпадающей с объявленной в объекте. –

+0

Разве ваше второе альтернативное решение не нарушает правила? Это пример того, как не делать этого. –

+0

Я тоже, @ Джерри, но я набираю это на своем телефоне, поэтому я не хочу беспокоиться больше, чем мне нужно. –