Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> по Mutex: есть вариант, когда не работает, из дебрей синхронизации 
:(
    Опции темы
Ibragim
Дата 13.12.2006, 22:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 28.9.2004
Где: Киев

Репутация: нет
Всего: нет



Вечер добрый. Вот надыбал ситуацию, когда Mutex ведет себя не так как хотелось бы. Точнее даже не Mutex, а WaitForSingleObject

Вот код

Код

  TForm1 = class(TForm)       // На форме одно TMemo и две кнопки
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
<....>

TMyThread = class(TThread)
  procedure Execute; override;
  procedure OnButton2(Sender: TObject);
end;

var
  Form1: TForm1;
  Mutex: THandle;
  t1,t2,t3: TMyThread;

implementation

{$R *.dfm}

procedure TMyThread.Execute;
begin
  WaitForSingleObject(Mutex, INFINITE);
  Form1.Memo1.Lines.Add('Hello world');
  Form1.Button2.OnClick := OnButton2;
end;

procedure TMyThread.OnButton2(Sender: TObject);
begin
  ReleaseMutex(Mutex);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Mutex := CreateMutex(NIL, false, 'MyMutex');
  if Mutex = 0 then
    RaiseLastWin32Error;

  t1 := TMyThread.Create(false);
  t2 := TMyThread.Create(false);
  t3 := TMyThread.Create(false);
end;



По задумке потоки ждут нажатия кнопки оператором, для того чтобы начать вывод. Однако этого не происходит - выводится все три надписи сразу. В описании функции WaitForSingleObject вычитал (DRKB), что она каким-то образом прекращает ожидание, если поток завершился и при этом даже НЕ освободил Mutex. 
Кто посоветует, как это обойти?
Как сделать, чтобы, несмотря на то что выполнение Execute закончилось, остальные потоки все равно ждали ПРЯМОГО УКАЗАНИЯ что можно выводить (ReleaseMutex(Mutex);)?

Заранее спасибо.
PM MAIL   Вверх
Alexeis
Дата 14.12.2006, 00:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 109
Всего: 459



Опять же все обращения к VCL из второго потока можно делать только через Syncronize, все остальные вызовы опасны.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
bems
Дата 14.12.2006, 00:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 31
Всего: 88



использовать событие (event) вместо мьютекса


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Ibragim
Дата 14.12.2006, 01:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 28.9.2004
Где: Киев

Репутация: нет
Всего: нет



Цитата(bems @  14.12.2006,  00:57 Найти цитируемый пост)
использовать событие (event) вместо мьютекса


Event мне нельзя или я просто не знаю как его применить к такому случаю. Здесь сотни потоков ожидают одного события - освобождения оператора. Насколько я понимаю, такая ситуация решается именно мьютексами. Если я не прав - поправь плз.

Цитата(alexeis1 @  14.12.2006,  00:44 Найти цитируемый пост)
Опять же все обращения к VCL из второго потока можно делать только через Syncronize, все остальные вызовы опасны


Если это не долго и тебе не сложно, приведи пример плз. Достаточно не программы, а двух ключевых операторов - типа там создаем семафор/мьютекс/т.п, там ждем того-то.

Это сообщение отредактировал(а) Ibragim - 14.12.2006, 02:24
PM MAIL   Вверх
Ibragim
Дата 14.12.2006, 02:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 28.9.2004
Где: Киев

Репутация: нет
Всего: нет



Даже не так. Вот исходник тестовой проги. Единственое обращение к VCL через Syncronize. Эффект тот же. Чего посоветуете?

Код


unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

TMyThread = class(TThread)
  procedure Execute; override;
  procedure Outtext;
end;


var
  Form1: TForm1;
  Mutex: THandle;
  t1,t2,t3: TMyThread;

implementation

{$R *.dfm}

procedure TMyThread.Execute;
begin
  WaitForSingleObject(Mutex, INFINITE);
  Synchronize(Outtext);
end;

procedure TMyThread.Outtext;
begin
  Form1.Memo1.Lines.Add('Ïîòîê ðàáîòàåò');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Mutex := CreateMutex(NIL, false, 'MyMutex');
  if Mutex = 0 then
    RaiseLastWin32Error;

  t1 := TMyThread.Create(false);
  t2 := TMyThread.Create(false);
  t3 := TMyThread.Create(false);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ReleaseMutex(Mutex);
end;

end.

PM MAIL   Вверх
bems
Дата 14.12.2006, 03:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 31
Всего: 88



Цитата(Ibragim @  14.12.2006,  01:50 Найти цитируемый пост)
Здесь сотни потоков ожидают одного события - освобождения оператора. 
И когда освободиться, один из потоков займет мьютекс, а остальные будут ждать уже его.

А если с событием тогда
1. создал событие (CreateEvent).
2. создал потоки, вызывающие WaitForSingleObject с хэндлом события
3. по нажатию кнопки (как в примере) вызываешь SetEvent
4. все ждущие потоки  выполняются дальше

Добавлено @ 03:33 
Цитата(Ibragim @  14.12.2006,  02:05 Найти цитируемый пост)
procedure TForm1.Button2Click(Sender: TObject);
begin
  ReleaseMutex(Mutex);
end;

если эта процедура действительно вызывается как обработчик события (читай - из главного VCL потока) то тут ты пытаешся освободить мьютекс которым не владеешь.



--------------------
Обижено школьников: 8
PM MAIL   Вверх
bems
Дата 14.12.2006, 03:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 31
Всего: 88



Цитата(Ibragim @  13.12.2006,  22:46 Найти цитируемый пост)
 Mutex := CreateMutex(NIL, false, 'MyMutex');

вот тут false означает, что у вновь созданного мьютекса нет владельца. Раз так, то один из трех одинаковых потоков (который первым доберется до вызова WaitForSingleObject) моментально его дождется и захватит. Пока он будет рисовать надпись (ну или просто присваивать строку) другие два будут ждать. Когда он выйдет не освободив мьютекса, мьютекс будет щитаться брошенным и его дождется (захватит) слудующий поток
Цитата(Ibragim @  13.12.2006,  22:46 Найти цитируемый пост)
она каким-то образом прекращает ожидание, если поток завершился и при этом даже НЕ освободил Mutex
Если бы этого не происходило оставшиеся два потока зависли бы. Тебе этого надо?

Вобщем нужный эффект будет если ты тут
Цитата(Ibragim @  13.12.2006,  22:46 Найти цитируемый пост)
 Mutex := CreateMutex(NIL, false, 'MyMutex');
заменишь false на true. Тогда владельцем свежего мьютекса будет поток который его создал (первичный поток процесса, VCL - поток). По нажатию кнопки он же его освободит, и по очереди(!!!!!!!) начнут просыпаться те три потока (один сделал дело и завершился - проснулся другой) Будет выглядеть как будто они проснулись одновременно, поскольку работают очень не долго. Но более правильно будет тут использовать эвент, а мьютексы оставить для случая когда ни один из этих трех потоков не должен что-то делать одновременно с другими (MUTual EXclusive access - взаимоисключающий доступ)



--------------------
Обижено школьников: 8
PM MAIL   Вверх
bems
Дата 14.12.2006, 04:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 31
Всего: 88



и для синхронизации в пределах одного процесса есть более быстрые способы чем объекты ядра. Смотри критические секции и interlocked-функции


--------------------
Обижено школьников: 8
PM MAIL   Вверх
Ibragim
Дата 15.12.2006, 00:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 28.9.2004
Где: Киев

Репутация: нет
Всего: нет



Большое спасибо bems ! 
Все гуд, разобрался. 
На всякий случай (для тех у кого возникнет такой же вопрос) напишу как сделал.

1. В одном из потоков TThread (менеджер потоков, ссылку на него и так имели ВСЕ потоки) создал
переменную - объект TCriticalSection.
2. Везде, где потокам нужно было для продолжения, завершения работы, показа результатов выполнения и т.д. (у меня около 500 потоков, причем более 20 классов - "видов" потоков) вмешательство оператора - Enter в эту CriticalSection. После - Leave. Работает, даже если Leave вызывается из совершенно другого потока, а тот который сказал Enter давно завершен.

Все, тему можно считать закрытой, спасибо всем особенно bems.

PS Много предупреждений насчет обращений к визуальным компонентам из-под других потоков. Точно проверено (оч. громоздкие задачи, прямо стресс-тест smile )
1. Все нормально без всякой синхронизации работает если писать/читать поля TStringGrid, естественно, не одно поле одновременно.
2. Отлично работает TMemo.Add
3. Отлично работает StatusBar
PM MAIL   Вверх
bems
Дата 15.12.2006, 01:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 31
Всего: 88



Цитата(Ibragim @  15.12.2006,  00:55 Найти цитируемый пост)
PS Много предупреждений насчет обращений к визуальным компонентам из-под других потоков. Точно проверено (оч. громоздкие задачи, прямо стресс-тест  )
1. Все нормально без всякой синхронизации работает если писать/читать поля TStringGrid, естественно, не одно поле одновременно.
2. Отлично работает TMemo.Add
3. Отлично работает StatusBar 
это тебе пока везет. НЕЛЬЗЯ!



--------------------
Обижено школьников: 8
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0850 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.