![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
critical section timeouts [D7, XP, 2003]
SkyN © (2008-10-03 16:15:00)Требуется, чтобы после deadlock'а программа продолжала работать
i := 0;
while (not TryEnterCriticalSection(FLock))and(i<100) do begin
sleep(100);
inc(i);
end;
if i=100 then Raise Exception.Create('Deadlock');
правильно ли я решаю задачу?
более простого способа нет?
PS: о том, что таких ситуаций допускать нельзя, я знаю
guav (2008-10-16 17:07:00) [1]:-) Точно, не знал
han_malign (2008-10-16 17:02:00) [2]Болеете???
to release its ownership, the thread must call ReleaseMutex one time for each timethat it obtained ownership (either through CreateMutex or a wait function).
guav (2008-10-16 16:39:00) [3]> Ну а теперь задача давать доступ на чтения для любого количества
> потоков, а для записи, захватывать монопольно.
TMultiReadExclusiveWriteSynchronizer, TSimpleRWSync в Delphi.
Другие реализации: SWMRG Рихтера, boost::shared_butex из Boost.Thread, Slim Reader/Writer (SRW) Locks в Висте.
SkyN (2008-10-16 15:55:00) [4]спасибо guav, это работает
добавлю, для будущих поколений, что в конструкторе надо
FMutex := CreateMutex(nil, False, nil);
FRecursionCount := 0;
FThd := 0;
a уничтожая объект
CloseHandle(FMutex);
Ну а теперь задача давать доступ на чтения для любого количества потоков, а для записи, захватывать монопольно. Но это уже тема следующей ветки :)
guav (2008-10-16 10:20:00) [5]> [10] SkyN (16.10.08 09:45)
> Недостатком Mutex, по сравнению с КС, считаю сложность рекурсии
> из одного потока, возможно я ошибаюсь.
ошибаешься. из нерекурсивного мьютекса легко сделать рекурсивный.
пишу прямо сюда, может и не скомпилится, но идея, думаю, понятна.
type
TRecursiveMutex = class(TObject)
FMutex: THandle;
FRecursionCount: Integer;
FThd: DWORD;
function Lock(Timeout: DWORD): Boolean;
procedure Unlock();
end;
function TRecursiveMutex.Lock(Timeout: DWORD): Boolean;
begin
if GetCurrentThreadId() = FThd then
begin
Inc(FRecursionCount);
Result := True;
end
else
Result := WAIT_OBJECT_0 = WaitForSingleObject(FMutex, Timeout);
if Result then
begin
InterlockedExchange(@FThd, GetCurrentThreadId());
Inc(FRecursionCount);
end;
end;
end;
procedure TRecursiveMutex.Unlock()
begin
Dec(FRecursionCount);
if 0 = FRecursionCount then
begin
InterlockedExchange(@FThd, 0);
ReleaseMutex(FMutex);
end;
end;
> [10] SkyN (16.10.08 09:45)
> Неужели нет стандартных, устоявшихся кодов для данной задачи?
Знаю такой, но не для Delphi.
SkyN (2008-10-16 09:45:00) [6]Почему код [6] с изменениями [8] не будет работать? поправьте меня, в чем я ошибаюсь:
1) Пытаюсь войти в КС
2) Если не вышло, то ожидаю сообщения об освобождении критической секции, но не больше таймаута
3) Если дождался сообщения об освобождении КС пытаюсь её захватить
4) Случился таймаут при ожидании события освобождения КС, сообщаю об ошибке
Недостатком Mutex, по сравнению с КС, считаю сложность рекурсии из одного потока, возможно я ошибаюсь.
Неужели нет стандартных, устоявшихся кодов для данной задачи?
guav (2008-10-09 22:46:00) [7]КС не позволяет ожидать с таймаутом. (EXCEPTION_POSSIBLE_DEADLOCK исключительно для отладки). Ни код [8], ни последующие попытки с TryEnterCriticalSection работать не будут.
Mutex.
(Если уж нужно снизить оверхед, при этом блокировки редки, можно реализовать КС самостоятельно через Event и Interlocked функции).
SkyN (2008-10-09 17:59:00) [8]Понял, что цикл должен быть таким:
while (not TryEnterCriticalSection(fCriticalSection))and(WR=WAIT_OBJECT_0) do begin
trace(ClassName+'.wait');
WR := WaitForSingleObject(fEvent, fDeadlockTime);
ResetEvent(fEvent);
end;
т.к. если есть рекурсия, то unlock будет вызываться несколько раз и SetEvent(fEvent) произойдет до освобождения КС.
Сейчас про Mutex почитаю
han_malign (2008-10-09 17:52:00) [9]Mutex
SkyN (2008-10-09 17:45:00) [10]Спасибо, вот такое решение у меня получилось:
type
tCriticalSection = class
private
fDeadlockTime : Integer;
fCriticalSection : TRTLCriticalSection;
fEvent : THandle;
public
constructor Create(const DeadlockTime: Integer = 10000);
destructor Destroy; override;
procedure lock;
procedure unlock;
published
property DeadlockTime: integer read fDeadlockTime write fDeadlockTime;
end;
constructor tCriticalSection.Create(const DeadlockTime: Integer = 10000);
begin
inherited Create;
InitializeCriticalSection(fCriticalSection);
fEvent := CreateEvent(nil, True, False, nil);
fDeadlockTime := DeadlockTime;
trace(ClassName+': tCriticalSection.Create');
end;
destructor tCriticalSection.Destroy;
begin
CloseHandle(fEvent);
DeleteCriticalSection(fCriticalSection);
trace(ClassName+': tCriticalSection.Destroy');
inherited Destroy;
end;
procedure tCriticalSection.lock;
var
W: Integer;
begin
W := WAIT_OBJECT_0;
ResetEvent(fEvent);
while (not TryEnterCriticalSection(fCriticalSection))and(WR=WAIT_OBJECT_0) do begin
trace(ClassName+'.wait');
W := WaitForSingleObject(fEvent, fDeadlockTime);
end;
if W = WAIT_OBJECT_0 then trace(ClassName+'.Lock')
else Raise Exception.Create(ClassName+': Deadlock WR='+IntToStr(WR));
end;
procedure tCriticalSection.unlock;
begin
trace(ClassName+'.Unlock');
LeaveCriticalSection(fCriticalSection);
SetEvent(fEvent);
end;
что скажете?
WaitForSingleObject(tCriticalSection, fDeadlockTime) я же не могу сделать?
Насколько я понял из ссылки, этот время для EXCEPTION_POSSIBLE_DEADLOCK будет одинаковое для всей системы, а хотелось бы менять его в зависимости от объекта.
guav (2008-10-05 10:44:00) [11]поймёт и в ближайшем except отранслирует в EExternalException, несмотря на то что по ссылке выше написано "Do not handle a possible deadlock exception; instead, debug the application."
Cobalt (2008-10-05 09:08:00) [12]А Дельфи поймёт это исключение?
guav (2008-10-03 22:17:00) [13]> правильно ли я решаю задачу?
Нет.
TryEnterCriticalSection + Sleep - это не ожидание КС.
В стандартной КС не предусмотрено ожидание с таймаутом. (Хотя, исключение при дедлоке по таймауту предусмотрено, см EXCEPTION_POSSIBLE_DEADLOCK http://msdn.microsoft.com/en-us/library/ms682608(VS.85).aspx ).
Согласен с
> [2] Rouse_ © (03.10.08 17:44)
Rouse_ (2008-10-03 17:44:00) [14]
if WaitForSingleObject() = WAIT_TIMEOUT then
Сергей М. (2008-10-03 16:16:00) [15]а где тут дедлок ?
В упор не вижу ..