• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Thread Synchronization

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Сообщения
1,163
Симпатии
222
Баллы
155
VK
If you have created a class template automatically, you may have noticed a comment that Delphi friendly place in the new module. It states: "Methods and properties of objects in visual components can only be used in a method called using Synchronize". This means that an appeal to the visual components is only possible by calling procedure Synchronize. Let's look at an example, but now our thread will not heat up the CPU for nothing, and will do something useful, for example, scrolling ProgressBar on the form. The parameter passed to the procedure Synchronize method of our stream, but he passed no parameters. Parameters can be passed by adding the desired field type in a description of our class. We will have one field - the same progress:
Если вы создали шаблон класса автоматически, то, наверное, заметили комментарий, который дружелюбная Delphi поместила в новый модуль. Он гласит: "Methods and properties of objects in visual components can only be used in a method called using Synchronize". Это значит, что обращение к визуальным компонентам возможно только путём вызова процедуры Synchronize. Давайте рассмотрим пример, но теперь наш поток не будет разогревать процессор впустую, а будет делать что-нибудь полезное, к примеру, прокручивать ProgressBar на форме. В качестве параметра в процедуру Synchronize передаётся метод нашего потока, но сам он передаётся без параметров. Параметры можно передать, добавив поля нужного типа в описание нашего класса. У нас будет одно поле - тот самый прогресс:
Код:
TNewThread = class(TThread)
  private
    Progress: integer;
    procedure SetProgress;
  protected
    procedure Execute; override;
  end;
...

procedure TNewThread.Execute;
var
  i: integer;
begin
  for i:=0 to 100 do
  begin
    sleep(50);
    Progress:=i;
    Synchronize(SetProgress);
  end;
end;

procedure TNewThread.SetProgress;
begin
  Form1.ProgressBar1.Position:=Progress;
end;
Now ProgressBar is moving and it is quite safe. A safe here's why: Synchronize procedure to suspend execution time of our stream, and transfers control to the main thread, ie SetProgress executed on the main thread. It is necessary to remember, because some mistakes, performing inside Synchronize long-term work, with, obviously, the form freezes for a long time. Therefore, use Synchronize to display information - the same dviganie progress update header components, etc.

You have probably noticed that inside the loop, we use the procedure Sleep. In single-threaded application Sleep is rarely used, but in the flow of it is very convenient to use. Example - an endless loop until you do some sort of condition. If you do not insert Sleep there we'll just load the system useless work.

I hope you understand how it works Synchronize. But there is another fairly easy way to transfer information form - sending a message. Let's look at it as well. To do this, declare a constant:
Вот теперь ProgressBar двигается, и это вполне безопасно. А безопасно вот почему: процедура Synchronize на время приостанавливает выполнение нашего потока, и передаёт управление главному потоку, т.е. SetProgress выполняется в главном потоке. Это нужно запомнить, потому что некоторые допускают ошибки, выполняя внутри Synchronize длительную работу, при этом, что очевидно, форма зависает на длительное время. Поэтому используйте Synchronize для вывода информации - то самое двигание прогресса, обновления заголовков компонентов и т.д.

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

Надеюсь, вы поняли как работает Synchronize. Но есть еще один довольно удобный способ передать информацию форме - посылка сообщения. Давайте рассмотрим и его. Для этого объявим константу:
Код:
const
  PROGRESS_POS = WM_USER+1;
In the class declaration form to add a new method, and then its implementation:
В объявление класса формы добавим новый метод, а затем и его реализацию:
Код:
TForm1 = class(TForm)
    Button1: TButton;
    ProgressBar1: TProgressBar;
    procedure Button1Click(Sender: TObject);
  private
    procedure SetProgressPos(var Msg: TMessage); message PROGRESS_POS;
  public
    { Public declarations }
  end;
...

procedure TForm1.SetProgressPos(var Msg: TMessage);
begin
  ProgressBar1.Position:=Msg.LParam;
end;
Now we have a little change, you can even say simplify the implementation of the Execute method of our stream:
Теперь мы немного изменим, можно сказать даже упростим, реализацию метода Execute нашего потока:
Код:
procedure TNewThread.Execute;
var
  i: integer;
begin
  for i:=0 to 100 do
  begin
    sleep(50);
    SendMessage(Form1.Handle,PROGRESS_POS,0,i);
  end;
end;
Using the SendMessage, we send a message window applications, one of which contains the parameters you want us to progress. A message is queued, and according to this queue will be processed by the main thread, where the method is executed SetProgressPos. But there is a caveat: SendMessage, as is the case with Synchronize, suspend the execution of our stream, while the main thread does not process the message. If you use PostMessage this does not happen, we will send a message stream and continue to work, and only when it is parsed out there - it does not matter. Which of these functions to use - you decide, it all depends on the task.

That is, in principle, we have considered the main ways to work with VCL components of the streams. And what if our program is not a new thread, but several? And you have to organize your work with the same data? Here we come to the aid of other methods of synchronization. One of them we consider. For its implementation must be added to the project module SyncObjs.
Используя функцию SendMessage, мы посылаем окну приложения сообщение, один из параметров которого содержит нужный нам прогресс. Сообщение становится в очередь, и согласно этой очереди будет обработано главным потоком, где и выполнится метод SetProgressPos. Но тут есть один нюанс: SendMessage, как и в случае с Synchronize, приостановит выполнение нашего потока, пока основной поток не обработает сообщение. Если использовать PostMessage этого не произойдёт, наш поток отправит сообщение и продолжит свою работу, а уж когда оно там обработается - неважно. Какую из этих функций использовать - решать вам, всё зависит от задачи.

Вот, в принципе, мы и рассмотрели основные способы работы с компонентами VCL из потоков. А как быть, если в нашей программе не один новый поток, а несколько? И нужно организовать работу с одними и теми же данными? Тут нам на помощь приходят другие способы синхронизации. Один из них мы и рассмотрим. Для его реализации нужно добавить в проект модуль SyncObjs.
 
Вверх Снизу