Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как сделать чтобы форма реагировала во время работы потоков. [D7, WinXP]


Страницы:   1 2 3 4

Kolan ©   (2005-05-27 10:09:00) 

Здравствуйте,
 Разбираюсь с потоками, нашел статью:
http://www.realcoding.net/article/view/158
Сделал пример где два потока, один включает флажок CheckBox'а другой выключает.
Если я всё правильно понял, то потоки должны работать себе и работать а форма нормально реагировать на все события.

Но форма как будто висит. Точнее мне всёже удалось передвинуть её, но переместилась она с большой задержкой.

Вот код потока:

type
 TMyThread1 = class(TThread)
 private
    { Private declarations }
 protected
   procedure DoWork;
   procedure Execute; override;
 end;


procedure TMyThread1.Execute;
begin
while not Terminated do
 Synchronize(DoWork);
end;

procedure TMyThread1.DoWork;
begin
 Form1.CheckBox.Checked := True;
end;

Ну соотвественно второй
Form1.CheckBox.Checked := False;

Код главного юнита.

var
 Form1: TForm1;
  T1: TMyThread1;
  T2: TMyThread2;


На форме одна кнопка:
procedure TForm1.StopButtonClick(Sender: TObject);
begin
 if StopButton.Caption = 'Ñòîï' then
 begin
   {Ïðåðûâàåì îáà ïðîöåññà}
   T1.Terminate;
   T2.Terminate;
   StopButton.Caption := 'Ñòàðò';
 end
 else
 begin
   {Ñîçäàåì è ñðàçó çàïóñêàåì äâà ïðîöåññà}
   T1 := TMyThread1.Create(False);
   T2 := TMyThread2.Create(False);

   StopButton.Caption := 'Ñòîï';
 end;
end;


Что я нетак понял или сделал?


Игорь Шевченко   (2005-05-27 12:24:00) [41]


> Изменять значение FIinterval могут несколько потоков одновременно.


Это как ? Переменная же является приватной для каждого потока ?


Kolan   (2005-05-27 12:18:00) [42]

Благодарю за ответы.

На самом деле
 Я хочу написать dll. Для работы с Com портом. С записью проблем нет. Вот чтение хочу сделать в потоке. Нашел статью
http://articles.org.ru/docum/comport.php
И решил для начала разабраться с потоками. Мне подсказали что можно использовать механизм сообшений. Однако если я хочу работать в режиме: "послал команду, получил ответ(ответ 2-3байта), обработал", то этот подход непройдет, так как медленно, и надо делать буфер итд.

Как можно решить эту проблемму. Хотелось бы именно работать в режиме послал принял. Скорость порта 115200. И именно dll. чтобы изменить если что.


Erik1   (2005-05-27 12:16:00) [43]

А вобщето господину "Карих Николай" - это автор статьи, надо яйца отрезать. За глубокое непонимание потоков и их синхронизации, а то, что он читает Архангельский, тоглько усигубляет его вину и неможет служить смягчающим обстоятельством.
 Вывод: Неходи больше на этот сайт и не читай глупости.


-=XP=-   (2005-05-27 12:15:00) [44]

Изменять значение FIinterval могут несколько потоков одновременно.

Это понятно. Просто FInterval имеет тип Cardinal. Насколько я понимаю, защита читаемой/записываемой памяти реализована на уровне ОС, если не процессора(ов). То-есть, в любом случае будет записано/прочитано верное значение. В смысле, потоки не будут, в случае возникновения конкурентной ситуации, портить (именно портить) данные. То-есть, если в один момент времени два потока решат писать в эту переменную данные, то после того, как они оба завершат сие действие, в переменной останется последнее записанное значение (не важно кем). Мусор там, по идее не появится. Под "мусором" я имею в виду: писали из одного потока 10, из другого 20, а получили в переменной 18.
Или, все же, такая ситуация может произойти?

Я так думаю, критическую секцию надо использовать только тогда, когда необходимо выполнить несколько неразрывно связанных последовательных действий. Например, одновременно установить значения нескольких переменных. В таком случае критическая секция необходима для обеспечения непротиворечивости значений этих переменных. То-есть, когда между изменениями двух (логически) связанных переменных процесоор может переключится на выполнение другого потока. То-есть, некое подобие "транзакции" (прошу прощения за подобную аналогию, но мне кажется, здесь есть сходство).

Хотя, и в [16] она не принесет вреда, разве что некоторое небольшое сокращение производительности.


Alexander Panov   (2005-05-27 12:00:00) [45]

-=XP=- ©   (27.05.05 11:52) [17]
используется критическая секция? Или это для примера?


Изменять значение FIinterval могут несколько потоков одновременно.


-=XP=-   (2005-05-27 11:52:00) [46]

Извините, может, я и не прав, но зачем в

procedure TTestThread.SetInterval(const Value: Cardinal);
function TTestThread.GetInterval: Cardinal;

используется критическая секция? Или это для примера?


Alexander Panov   (2005-05-27 11:45:00) [47]

Посмотри на такой пример.

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, SyncObjs;

type
 TForm1 = class(TForm)
   CheckBox1: TCheckBox;
   Button1: TButton;
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

 TTestThread=class(TThread)
 private
   FCS: TCriticalSection;
   FCB: TCheckBox;
   FInterval: Cardinal;
   FChecked: Boolean;

   procedure Lock;
   procedure Unlock;
   function GetInterval: Cardinal;
   procedure SetInterval(const Value: Cardinal);
   procedure _Sleep;
 protected
   procedure UpdateControl;
   procedure Execute; override;
 public
   constructor Create(Control: TCheckBox; Interval: Cardinal; Checked: Boolean);
   destructor Destroy; override;

   property Interval: Cardinal read GetInterval write SetInterval;
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

{ TTestThread }

constructor TTestThread.Create(Control: TCheckBox; Interval: Cardinal;
 Checked: Boolean);
begin
 inherited Create(True);
 Randomize;
 FCS := TCriticalSection.Create;
 FCB := Control;
 FInterval := Interval;
 FChecked := Checked;
 FreeOnTerminate := True;
 Resume;
end;

destructor TTestThread.Destroy;
begin
 FCS.Free;
 inherited;
end;

procedure TTestThread.Execute;
begin
 while not Terminated do
 begin
   Synchronize(UpdateControl);
   _Sleep;
 end;
end;

function TTestThread.GetInterval: Cardinal;
begin
 Lock;
 try
   Result := FInterval;
 finally
   Unlock;
 end;
end;

procedure TTestThread.Lock;
begin
 FCS.Enter;
end;

procedure TTestThread.SetInterval(const Value: Cardinal);
begin
 Lock;
 try
   FInterval := Value;
 finally
   Unlock;
 end;
end;

procedure TTestThread.Unlock;
begin
 FCS.Leave;
end;

procedure TTestThread.UpdateControl;
begin
 FCB.Checked := FChecked;
end;

procedure TTestThread._Sleep;
var
 Times: Cardinal;
begin
 if FInterval=0
   then Times := 10+Random(200)
   else Times := FInterval;
 Sleep(Times);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
 t1,t2: TTestThread;
begin
 t1 := TTestThread.Create(CheckBox1,0,True);
 t2 := TTestThread.Create(CheckBox1,0,False);
end;

end.


TUser   (2005-05-27 11:33:00) [48]

> Polevi ©   (27.05.05 11:25) [12]
> Игорь Шевченко ©   (27.05.05 11:29) [13]

А что он сказал не так? Весь Execute не синхронизируется, синхронизируется только метод, который работает с VCL - как и должно быть.
Другой вопрос, что для такой цели отд. поток не нужен, но если все-таки потоком это делать, то я не понял, где в [11] ошибка.


-=XP=-   (2005-05-27 11:29:00) [49]

Polevi ©   (27.05.05 11:25) [12]

Можно поподробнее?


Игорь Шевченко   (2005-05-27 11:29:00) [50]

Архангельский маст дай.


Polevi   (2005-05-27 11:25:00) [51]

>-=XP=- ©   (27.05.05 10:42) [11]
иногда лучше жевать, ей богу


-=XP=-   (2005-05-27 10:42:00) [52]

В Вашем примере:

Следующий код выполняется в отдельном потоке:
procedure TMyThread1.Execute;
begin
while not Terminated do
Synchronize(DoWork); // Вызывается метод Synchronize для синхронизации с основным потоком
end;


Весь следующий метод выполняется в основном потоке:
procedure TMyThread1.DoWork;
begin
Form1.CheckBox.Checked := True;
end;


Поэтому, если Вы напишите Sleep() в методе DoWork, то тем самым "усыпите" основной поток. Насколько я понял, Вам не это нужно? Поэтому пишите Sleep() в том месте, где "усыпление" дополнительного потока не вызовет "усыпление" основного потока, то есть, вне методов, вызванных через Synchronize().

Итого:

procedure TMyThread1.Execute;
begin
 while not Terminated do
 begin
   Synchronize(DoWork);
   Sleep(100); // Заснет только этот поток; основной поток продолжит выполнение.
 end;
end;

procedure TMyThread1.DoWork;
begin
 Form1.CheckBox.Checked := True;
end;


Kolan   (2005-05-27 10:39:00) [53]


> begin...end ©   (27.05.05 10:37) [8]

Угу, посмотрю. :)


Kolan   (2005-05-27 10:38:00) [54]

Всем подходит, я хочу понять просто как потоки использовать.


begin...end   (2005-05-27 10:37:00) [55]

> Kolan ©   (27.05.05 10:20) [5]

> Где взять хороший

{Delphi}\Demos\Threads


-=XP=-   (2005-05-27 10:26:00) [56]

Простой пример можно?

Чем [1] не подходит?


Kolan   (2005-05-27 10:21:00) [57]


> Bel ©   (27.05.05 10:17) [4]

Простой пример можно?


Kolan   (2005-05-27 10:20:00) [58]


> ЮЮ ©   (27.05.05 10:15) [2]


Не понял. Просто этот пример работы с потоками неудачный?

<quote из источника>
А теперь - замечательный пример для изучения Thread! В нижеследующем примере приложение создает два параллельно работающих процесса. Один Thread пытается установить флажок CheckBox1 в положение "включено" (Checked := True), а другой, передергивая первого - в "выключено".
</quote из источника>


Где взять хороший


Bel   (2005-05-27 10:17:00) [59]

Естественно, форма будет тормозить, ведь Syncronize работает в контексте основного потока. Обычно в параллельный поток выносят действия, не связанные с интерфейсом, тогда главная форма тормозить не будет.


Kolan   (2005-05-27 10:16:00) [60]

Гы я почти так и пытался, но сделал так:

procedure TMyThread1.DoWork;
begin
 Form1.CheckBox.Checked := True;
 Sleep(100);
end;


Страницы:   1 2 3 4

Наверх

Титульная страница Поиск, карта сайта Написать письмо