Как говорит Роб, единственное требование состоит в том, чтобы убедиться, что критический раздел в настоящее время не принадлежит ни одному потоку. Даже не нить о том, чтобы уничтожить его. Таким образом, нет шаблона для правильного уничтожения TCriticalSection как такового. Только обязательное поведение, для обеспечения которого ваше приложение должно предпринять шаги.
Если ваше приложение блокируется, то я сомневаюсь, что это связано с освобождением какого-либо критического раздела. Как говорит MSDN (в ссылке, которую разместил Роб), DeleteCriticalSection() (что в конечном итоге является тем, что освобождает вызовы TCriticalSection) не блокирует никаких потоков.
Если бы вы освободили критическую секцию, к которой все еще пытались получить доступ другие потоки, вы бы получили нарушения прав доступа и другие непредвиденные ситуации, а не взаимоблокировки, как этот небольшой пример кода должен помочь вам продемонстрировать:
implementation
uses
syncobjs;
type
tworker = class(tthread)
protected
procedure Execute; override;
end;
var
cs: TCriticalSection;
worker: Tworker;
procedure TForm2.FormCreate(Sender: TObject);
begin
cs := TCriticalSection.Create;
worker := tworker.Create(true);
worker.FreeOnTerminate := TRUE;
worker.Start;
sleep(5000);
cs.Enter;
showmessage('will AV before you see this');
end;
{ tworker }
procedure tworker.Execute;
begin
inherited;
cs.Free;
end;
Добавьте в модуль реализации формы, при необходимости исправив ссылку "TForm2" для обработчика события FormCreate().
В FormCreate() это создает критическую секцию, а затем запускает поток, единственной целью которого является освобождение этой секции. Мы вводим задержку Sleep(), чтобы дать потоку время для инициализации и выполнения, затем мы пытаемся войти в критическую секцию самостоятельно.
Мы не можем, конечно, потому что он был свободен. Но наш код не зависает — он не заблокирован при попытке доступа к ресурсу, который принадлежит кому-то другому, он просто взрывается, потому что мы пытаемся получить доступ к ресурсу, которого больше не существует.
Вы могли бы быть еще более уверены в создании AV в этом сценарии, обнулив ссылку на критический раздел, когда он свободен.
Теперь попробуйте изменить код FormCreate() на это:
cs := TCriticalSection.Create;
worker := tworker.Create(true);
worker.FreeOnTerminate := TRUE;
cs.Enter;
worker.Start;
sleep(5000);
cs.Leave;
showmessage('appearances can be deceptive');
Это меняет дело... теперь основной поток будет владеть критическим разделом - теперь рабочий поток освободит критический раздел, пока он все еще принадлежит основному потоку.
Однако в этом случае вызов cs.Leave не обязательно вызывает нарушение прав доступа. Все, что происходит в этом сценарии (афакт), заключается в том, что потоку-владельцу разрешено «оставить» раздел, как он и ожидал (это, конечно, не так, потому что раздел исчез, но кажется к нитке, что она покинула раздел, в который ранее заходила)...
... в более сложных сценариях возможно нарушение прав доступа или другая ошибка, так как память, ранее использовавшаяся для объекта критической секции, может быть перераспределена какому-то другому объекту к тому времени, когда вы вызываете его метод Leave(), что приводит к некоторым вызов какого-либо другого неизвестного объекта или доступ к недопустимой памяти и т. д.
Опять же, изменение worker.Execute() так, чтобы оно было нулевой ссылкой на критическую секцию после освобождения, обеспечило бы нарушение прав доступа при попытке вызвать cs.Leave(), поскольку Leave() вызывает Release() и Release() является виртуальным - вызов виртуального метода со ссылкой NIL гарантирован для AV (то же самое для Enter(), который вызывает виртуальный метод Acquire()).
В любом случае:
В худшем случае: исключение или странное поведение
«Лучший» случай: кажется, что поток-владелец считает, что он «покинул» раздел как обычно.
Ни в том, ни в другом случае тупик или зависание не произойдет просто в результате освобождения критической секции в одном потоке по отношению к тому, когда другие потоки затем попытаются войти или выйти из этой критической секции.
Все это является косвенным способом сказать, что это звучит так, как будто у вас есть более фундаментальное состояние гонки в вашем многопоточном коде, не связанное напрямую с освобождением ваших критических секций.
В любом случае, я надеюсь, что моя небольшая исследовательская работа может направить вас на правильный путь.
person
Deltics
schedule
30.12.2010