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

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

Синхронизация в потоке [D7, Win2k]


Fedia ©   (2004-09-15 10:11:00) 

Вопрос такой.
Есть две процедуры. Например


procedure Second(Label1: TLabel);
begin
 Label1.Caption:='тест';
end;

procedure First(Label1: TLabel);
begin
 Second(Label1);
end;


Процедура First вызывается в потоке:


procedure TSQLThrd.Execute;
begin
 First(Form1.Label1);  
end;


Без синхронизации не безопасно менять свойства визуальных компонентов. Как мне произвести синхронизацию изменения заголовка Label1?


Fedia   (2004-09-16 01:28:00) [1]

Все, сделал, заработало.
Слава Богу я тут на предприятии не один программистом работаю, и один из сотрудников предприятия подсказал как сделать.
В раздел protected потока я добавил экземпляры визуальных компонентов, свойства которых необходимо менять в потоке, а также переменные, символизирующие меняемые свойства.

 TSQLThrd2 = class(TThread)
 protected
   Label1: TLabel;
   LCaption: String;
   PB: TGaugeCX; //это видоизмененный ProgressBar
   Position: Integer;
 public
   procedure ChengLabel;
   procedure ChangePB;
 end;

var
 TSQLThrd: TSQLThrd2;


Процедуры, в которых происходит изменение свойств визуальных компонентов

procedure TSQLThrd2.ChengLabel;
begin
 Label1.Caption:=LCaption;
end;

procedure TSQLThrd2.ChangePB;
begin
 PB.Position:=Position;
end;

Процедуры, в которых происходит синхронизация с основным потоком:

procedure MyLabelSynchronize(Label1: TLabel; s: String);
begin
 TSQLThrd.Label1:=Label1;
 TSQLThrd.LCaption:=s;
 TSQLThrd.Synchronize(TSQLThrd, TSQLThrd.ChengLabel);
end;

procedure MyPBSynchronize(PB: TGaugeCX; i: Integer);
begin
 TSQLThrd.PB:=PB;
 TSQLThrd.Position:=i;
 TSQLThrd.Synchronize(TSQLThrd, TSQLThrd.ChangePB);
end;


А вот замена процедуры Second из (15.09.04 10:11):  

procedure Second(Label1: TLabel);
begin
 //Label1.Caption:='тест'; //без синхронизации
 MyLabelSynchronize(Label1, 'тест'); //с использованием синхронизации
end;


Erik1   (2004-09-15 15:11:00) [2]

To panov
С этим полностью согласен, добавлю, что во все входит и главный поток.

To TUser
Ты сам смотрел Synchronize? Незаметил случайно вот такю строку SendMessage(ThreadWindow, CM_EXECPROC, 0, Longint(Self)) ? В Synchronize посылается сообщение созданому окну, а в обработчике сообщений ищется CM_EXECPROC и вызывается нужный метод. Поэтому Synchronize просто использует очередь сообщенией для синхронизации.


panov   (2004-09-15 11:45:00) [3]

>All
Код [5] некорректен, так как эту критическую секцию должны использовать все потоки при обращении к VCL.


Fedia   (2004-09-15 11:40:00) [4]

Я тут погрузился в разбор кода и был временно не доступен :)
TUser ©   (15.09.04 11:17) [9]
>> PS. Интересно, я угадал в чем проблема?
Мне интересно о чем тут было гадать? Хотя похоже ты не один гадал, следовательно косяк мой.
Я не могу переделывать все процедуры в методы потока. Слишком много кода придется менять. Поэтому хотел изобрести хитрую ссылку на  Synchronize, чтобы заменить все строки типа:
Label1.Caption:='новый заголовок' на например
MySync(Label1, 'новый заголовок'), где MySync - процедура, в которой происходит синхронизация.

А на счет входа в критические секции сейчас попробую часть кода переделать и запустить на ночное тестирование. Если не упадет, переделаю остальное.


panov   (2004-09-15 11:27:00) [5]

>Erik1 ©   (15.09.04 11:15) [8]
Посмотри исходный код Synchronize


TUser   (2004-09-15 11:21:00) [6]


> Erik1 ©   (15.09.04 11:15) [8]

S сам использует критические секции.


TUser   (2004-09-15 11:17:00) [7]

Если хочешь через Synchr, не прописывая явно критические секции - то он вызывается из любого метода потока, который м.б. вызван из Execute. Особой разницы в его использовании нет. Другой вопрос - если все написано как у тебя в топике, т.к. First и Second - просто процедуры, а не методы класса. Они тогда ничего не знают про Synchronize, т.к. этот метод - из TThtread'а. Сделай их методами, и все будет хорошо.

PS. Интересно, я угадал в чем проблема?


Erik1   (2004-09-15 11:15:00) [8]

И как соотносится вход и выход в критическую секцию с синхнонизацией главного потока? При выполнении этого кода возможна ошибка. Cнхнонизация делается с использованием Synchronize или PostMessage.


panov   (2004-09-15 10:59:00) [9]

>Erik1 ©   (15.09.04 10:57) [6]
см. procedure TSimpleTimer.FTimer;


Erik1   (2004-09-15 10:57:00) [10]

To panov
Чегото я синхронизации невижу?


panov   (2004-09-15 10:38:00) [11]

>Fedia   (15.09.04 10:11)
Вот вчера писал, разбери пример и поймешь.


unit uSimpleTimer;

interface

uses
 Classes,windows;

type
 TProcTimer = procedure;
 TSimpleTimer = class(TThread)
 private
   FCS: RTL_CRITICAL_SECTION;
   FInterval: Integer;
   FOnTimer: TProcTimer;
   procedure FTimer;
   procedure SetOnTimer(Proc: TProcTimer);
 protected
   procedure Execute; override;
 public
   constructor Create(const aInterval: Integer);
   destructor Destroy;override;
   procedure Timer;
   property OnTimer: TProcTimer write SetOnTimer;
   procedure Start;
   procedure Stop;
   procedure Release;
 end;

implementation

procedure TSimpleTimer.Release;
begin
 Terminate;
 Resume;
end;

destructor TSimpleTimer.Destroy;
begin
end;

constructor TSimpleTimer.Create(const aInterval: Integer);
begin
 inherited Create(True);
 FreeOnTerminate := True;
 FInterval := aInterval;
end;

procedure TSimpleTimer.Start;
begin
 Resume;
end;

procedure TSimpleTimer.Stop;
begin
 Suspend;
end;

procedure TSimpleTimer.SetOnTimer(Proc: TProcTimer);
begin
 FOnTimer := Proc;
end;

procedure TSimpleTimer.Timer;
begin
 FOnTimer;
end;

procedure TSimpleTimer.FTimer;
begin
 if Assigned(FOnTimer) then
 begin
   EnterCriticalSection(FCS);
   FOnTimer;
   LeaveCriticalSection(FCS);
 end;
end;

procedure TSimpleTimer.Execute;
begin
 InitializeCriticalSection(FCS);
 try
   while not Terminated do
   begin
     Sleep(FInterval);
     if Terminated then Continue;
     FTimer;
   end;
 finally
   DeleteCriticalSection(FCS);
 end;
end;

end.


Вызов:


procedure MyOnTimer;
begin
 fMain.sbMain.Panels[0].Text := FormatDateTime('dd.mm.yyyy hh:nn:ss',now);
end;

procedure TfMain.FormCreate(Sender: TObject);
begin
 ST := TSimpleTimer.Create(1000);
 ST.OnTimer := MyOnTimer;
 ST.Timer;
 ST.Start;
end;

procedure TfMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 ST.Release;
end;


Суслик   (2004-09-15 10:32:00) [12]


> к сожалению, нужна помощь.

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

Делаешь просто:
1) Выделяешь 10 минут времени.
2) Обдумываешь вопрос (что надо получить, что уже сделал и пр.).
3) Выделяешь еще 10 минут.
4) Аккуратно его записываешь.
5) Ждешь ответа.

Тебя удивит тот факт, что ты получишь нормальный и полезный ответ.
Проверь.


Fedia   (2004-09-15 10:26:00) [13]

Ах ну конечно, как же я сразу не догадался :)
Если уж спрашиваю, так значит F1 мне не помог. Как сделать просто синхронизацию в Execute потока я разобрался, а вот как это сделать внутри вложенной процедуры не могу, к сожалению, нужна помощь.


TUser   (2004-09-15 10:24:00) [14]

Да еще написать Form1.Label1, а то компилятор будет ругаться


Defunct   (2004-09-15 10:13:00) [15]

Synchronize F1


Наверх

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