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

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Mutex, подробнее о мьютексах 
:(
    Опции темы
unReg
Дата 3.12.2003, 02:29 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Здравствуйте. Нашел в вашем форуме топик о мьютексах, но он оказался не совсем про мьютексы. Непонятно действие некоторых функций (в аглицком не силен). Мне нужно было синхронизировать доступ к файлу со стороны разных приложений. Одно приложение (1) создает и постоянно обновляет файл, а другое(ие) (2) просто читает его содержимое. (1) создает мьютекс в момент своего создания, а (2) берет хендл созданного мьютекса с помощью OpenMutex. Работа с файлом начинается после WaitForSingleObject (стандартный вариант). По окончании работы с файлом делаю ReleaseMutex и в (1) и в (2). CloseHandle делаю по Destroy (1).
И вот что получается:
1: работа с файлом синхронизируется. (это хорошо)
2: как уже говорилось-счетчик дескрипторов неуклонно растет пока работает (2)! (это плохо)
3: если я делаю в (2) CloseHandle после работы с файлом, то (1) затыкается на WaitForSingleObject. (а это вообще противоречит 2-му пункту).

Проблему 2 и 3 сейчас решаю так: при каждом обращении к файлу из (2), вместо OpenMutex делаю CreateMutex, потом WaitForSingleObject, потом ReleaseMutex и CloseHandle.
Нафиг тогда OpenMutex? если как написано в справке The OpenMutex function returns a handle of an existing named mutex object. Или я че-то неправильно понимаю?
  Вверх
unReg
Дата 4.12.2003, 03:08 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











OK. Наверное без кода никто не ответит. Каюсь.
Код потока (1) который создает мьютекс (каждый поток работает со своим файлом и своим MutexName):
Код


type TCThread=class(TThread)
private
  hMutex:THandle;
  F:TFileStream;
.....
public
 constructor ....
 destructor  ....
end;


constructor TCThread.Create(MutexName,FileName:string;ItemId:integer;CtrlCnfg:PCnfg);
var ...
begin
inherited Create(true);
.....
   hMutex:=CreateMutex(nil,False,PAnsiChar(MutexName));
.....
end;

procedure TCThread.Execute;
begin
  While not Terminated do
  begin
      if WaitForSingleObject(hMutex,0)<>wait_TimeOut then
           begin
             if not FileExists(FileName) then
              AnsFile:=TFileStream.Create(FileName,fmCreate)
             else
             AnsFile:=TFileStream.Create(FileName,fmOpenReadWrite);
             AnsFile.Seek(0,soFromBeginning);
             AnsFile.Write(BuffOut^,BuffOutLength);
             AnsFile.Free;
             ReleaseMutex(hMutex);
  end;
end;

destructor TCThread.Destroy;
begin
 ......
 CloseHandle(hMutex);
 ......
inherited Destroy;
end;


Теперь код приложения которое читает файл (2) первый вариант:
Код

.....
var hMutex:THandle; {глобальное объявление}
     FileName,MutexName:string;

.....

procedure TfrmMain.Timer1Timer(Sender: TObject);
var Buff:array [0..848] of byte;
begin
 hMutex:=OpenMutex(MUTEX_ALL_ACCESS,false,PAnsiChar(MutexName));
 if waitforsingleobject(hMutex,0)<>wait_timeout then
 begin
   F:=TFileStream.Create(FileName,fmOpenRead);
   F.Read(Buff,849);
   F.Free;
 end;
 ReleaseMutex(hMutex);
end;

Вот при таком раскладе растет счетчик дескрипторов.
Если после ReleaseMutex(hMutex); написать CloseHandle(hMutex), то (1) затыкается на waitforsingleobject (таймаут);
А если код (2) написать вот так (второй вариант):
Код

  procedure TfrmMain.Timer1Timer(Sender: TObject);
var Buff:array [0..848] of byte;
begin
 hMutex:=CreateMutex(nil,false,PAnsiChar(MutexName));
 if waitforsingleobject(hMutex,0)<>wait_timeout then
 begin
   F:=TFileStream.Create(FName,fmOpenRead);
   F.Read(Buff,849);
   F.Free;
 end;
 ReleaseMutex(hMutex);
 CloseHandle(hMutex);
 end;

тогда счетчик не увеличивается, и все вроде бы нормально, но!
Обнаружилась еще одна странность. Я попробовал вывести значение hMutex в Caption формы (caption:=inttostr(hMutex)) и в первом варианте кода (2) выходили разные(!) значения при каждой отработке процедуры, а во втором варианте значения одинаковые(!). Мало того, во втором варианте я откомпилил приложение (2) в нескольких вариантах (каждому потоку (1) соответствовал вариант приложения (2), естественно имена мьютексов и файлов различались в каждом потоке) и опять получил одинаковые значения hMutex во всех(!) запущенных приложениях (2). Вопрос, собственно, вот в чем: почему не работает первый вариант кода и че за ерунда с хендлами?

  Вверх
Dmitry V.Abramov
Дата 4.12.2003, 17:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Для начала вот это место:
Код
procedure TCThread.Execute;
begin
 While not Terminated do
 begin
     if WaitForSingleObject(hMutex,0)<>wait_TimeOut then
          begin
            if not FileExists(FileName) then
             AnsFile:=TFileStream.Create(FileName,fmCreate)
            else
            AnsFile:=TFileStream.Create(FileName,fmOpenReadWrite);
            AnsFile.Seek(0,soFromBeginning);
            AnsFile.Write(BuffOut^,BuffOutLength);
            AnsFile.Free;
            ReleaseMutex(hMutex);
 end;
end;


3 begin'a & 2 end'a - это нормально?
--------------------
/DVA
PM MAIL WWW   Вверх
p0s0l
Дата 4.12.2003, 21:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Г-н Посол
****


Профиль
Группа: Экс. модератор
Сообщений: 3668
Регистрация: 13.7.2003
Где: 58°38' с.ш. 4 9°41' в.д.

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



Попробуй в WaitForSingleObject вместо 0 поставить INFINITE, а так всё правильно, и в первом варианте второго кода нужно делать CloseHandle



--------------------
С уважением, г-н Посол.
PM   Вверх
Unregistered
Дата 5.12.2003, 02:09 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Dmitry V.Abramov нашел к чему прицепиться smile.gif

p0s0l Спасибо, но флаг infinite на сколько я понял заставляет ждать до тех пор пока не получит сигнала?
  Вверх
Ars
Дата 5.12.2003, 18:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Код
.....
var hMutex:THandle; {глобальное объявление}
    FileName,MutexName:string;

.....

procedure TfrmMain.Timer1Timer(Sender: TObject);
var Buff:array [0..848] of byte;
begin
hMutex:=OpenMutex(MUTEX_ALL_ACCESS,false,PAnsiChar(MutexName));
if waitforsingleobject(hMutex,0)<>wait_timeout then
begin
  F:=TFileStream.Create(FileName,fmOpenRead);
  F.Read(Buff,849);
  F.Free;
end;
ReleaseMutex(hMutex);
end;


Проблема в том, что при каждом вхождении ты получаешь новый дескриптор мьютекса и нигде его не освобождаешь. Поэтому у тебя всегда новое значение дескриптора и растет счетчик дескрипторов.
Я не понимаю, зачем вообще каждый раз получать дескриптор. Достаточно получить его однажды в начале работы приложения и хранить в данных TfrmMain или в глобальной переменной.

Функция OpenMutex, действительно, получает хэндл на существующий мьютекс, а если он не существует, то обламывается, в отличии от CreateMutex, которая или создает новый или открывает существующий (что именно, можно проверить последующим вызовом GetLastError). Tем самым устраняется необходимость последовательных вызовов OpenMutex, CreateMutex и проверок хэндлов для получения мьютекса. Кстати, у тебя нигде нет проверки на валидность хэндла...

Код
destructor TCThread.Destroy;
begin
......
ReleaseMutex(hMutex);       << Сюда неплохо бы вставить освобождение мьютекса
CloseHandle(hMutex);
......
inherited Destroy;
end;



--------------------
Есть многое на свете, друг Горацио,
С чем очень долго можно прое..!
PM MAIL   Вверх
Unregistered
Дата 8.12.2003, 01:55 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Спасибо. Тут чего-то действительно фигню спорол (каждый раз открывыл мьютекс). Это явно ни к чему.
В любом случае, господа, вы мне очень помогли. Еще раз - спасибо.
  Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

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

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

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

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


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

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


 




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


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

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