![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как сделать чтобы форма реагировала во время работы потоков. [D7, WinXP]
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;