Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Использование CriticalSection


Автор: bns12 10.9.2008, 17:16
Подскажите, пожалуйста, правильно ли я делаю:

1) я вставляю EnterCryticalSection первым оператором критической процедуры, к которой обращаюсь из нескольких потоков. Может быть, EnterCryticalSection нужно ставить перед командой потока, вызывающей эту процедуру?

2) я вставляю EnterCryticalSection первым оператором критической процедуры, к которой обращаюсь из нескольких потоков. При этом в процедуру передается параметр. При одновременном обращении к процедуре нескольких потоков параметры будут конфликтовать (затирать друг друга)?

3) я вставляю EnterCryticalSection первым оператором критической процедуры, к которой обращаюсь из нескольких потоков.  Чтобы избежать зависания использую TryEnterCriticalSection:
Код

procedure CriticalProcedure( const Param : integer );
var Cnt : integer;
begin
          Cnt := 0;
          while not TryEnterCriticalSection( CS ) do begin
             if Cnt = 10 then begin
                Exit;
             end;
             Sleep( 500 );
             Inc( Cnt );
          end;
          ...
          LeaveCriticalSEction( CS );
end;


Переменная Cnt будет общая для всех потоков или каждый поток работет со своей копией Cnt?

Спасибо.

Автор: bems 10.9.2008, 19:59
Цитата(bns12 @  10.9.2008,  17:16 Найти цитируемый пост)
Переменная Cnt будет общая для всех потоков или каждый поток работет со своей копией Cnt?
она лежит в стеке, а у каждого потока свой стек, поэтому тут все нормльно


Цитата(bns12 @  10.9.2008,  17:16 Найти цитируемый пост)
При одновременном обращении к процедуре нескольких потоков параметры будут конфликтовать (затирать друг друга)?
для типов не являющихся скрытыми указателями - все нормально, для являющихся - нормально при условии, что IsMultiThread=true

Автор: Felan 11.9.2008, 06:44
Цитата(bns12 @  10.9.2008,  19:16 Найти цитируемый пост)
3) я вставляю EnterCryticalSection первым оператором критической процедуры, к которой обращаюсь из нескольких потоков.  Чтобы избежать зависания использую TryEnterCriticalSection:

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

Если это у тебя VCL поток, и ты пытаешься избежать зависания пользовательского интерфейса, то в цикле надо сделать Application.ProcessMessage.

Цитата(bns12 @  10.9.2008,  19:16 Найти цитируемый пост)
Переменная Cnt будет общая для всех потоков или каждый поток работет со своей копией Cnt?

Со своей копией. Она тоже в стеке потока.

ЗЫЖ Вообще для входы/выходы из критических секций лучше всего в Try-Finally брать. ТАк... на всякий  случай.

Автор: Felan 11.9.2008, 07:00
Цитата(bems @  10.9.2008,  21:59 Найти цитируемый пост)
для типов не являющихся скрытыми указателями - все нормально, для являющихся - нормально при условии, что IsMultiThread=true 

Нет.
Эта переменная для менеджера памяти Delphi. К синхронизации она не имеет отношения.

Автор: bems 11.9.2008, 19:16
Цитата(Felan @  11.9.2008,  07:00 Найти цитируемый пост)
Эта переменная для менеджера памяти Delphi. К синхронизации она не имеет отношения.
как это не имеет? по твоему увеличить счетчик ссылок на строку (например при передаче ее в процедуру) можно одинаково в многопоточном и однопоточном приложениях?

Автор: bems 11.9.2008, 19:49
Прошу прощения, как оказалось счетчик ссылок строки всегда обрабатывается атомарно, даже если есть всего один поток.
Но при передаче интерфейса в процедуру (а точнее при выходе из нее) все равно нужен IsMultiThread

Код

procedure proc(a:IUnknown);
begin
//EnterCriticalSection
a:=TInterfacedObject.Create;
AllocConsole;
Writeln(dword(a));
//LeaveCriticalSection
end;//тут освобождение объекта, включающее FreeMem

procedure TForm1.Button1Click(Sender: TObject);
var o:TInterfacedObject;
begin     //IsMultiThread:=True;
o:=nil;
proc(o);
end;

Автор: Felan 12.9.2008, 07:44
Цитата(bems @  11.9.2008,  21:49 Найти цитируемый пост)
Но при передаче интерфейса в процедуру (а точнее при выходе из нее) все равно нужен IsMultiThread

Ну, во-первых, ниче не понял. По подробнее можно?

А во вторых, все, что ты говоришь, относится к менеджеру памяти и, вероятно, механизмам подсчета ссылок специфичным для делфи. А к синхронизации доступа к данным это отношения не имеет. Т.е. если два потока обращаются к одному ресурсу, неважно к какому, хоть десять раз IsMultiThread устанавливай, все равно нужна синхронизация.

Автор: bems 12.9.2008, 17:13
Цитата(Felan @  12.9.2008,  07:44 Найти цитируемый пост)
все, что ты говоришь, относится к менеджеру памяти и, вероятно, механизмам подсчета ссылок специфичным для делфи. А к синхронизации доступа к данным это отношения не имеет
то что я говорю относиться к внутренним структурам данных менеджера памяти, доступ к которым осуществляется с использованием критической секции, которой влядеет менеджер памяти. 

Топикстартер спрашивал нормально ли будет сделать так:
Цитата(bns12 @  10.9.2008,  17:16 Найти цитируемый пост)
procedure CriticalProcedure( const Param : integer );
var Cnt : integer;
begin
          Cnt := 0;
          while not TryEnterCriticalSection( CS ) do begin
             if Cnt = 10 then begin
                Exit;
             end;
             Sleep( 500 );
             Inc( Cnt );
          end;
          ...
          LeaveCriticalSEction( CS );
end;

В этом коде действия, подставляемые компилятором после начала процедуры но до первой строки пользовательского кода (и после последней строки но до возврата из процедуры) выполняются вне критической секции пользователя. Значит нужно включить использование критической секции менеджера памяти с помощью IsMultiThread

Цитата(Felan @  12.9.2008,  07:44 Найти цитируемый пост)
Т.е. если два потока обращаются к одному ресурсу, неважно к какому, хоть десять раз IsMultiThread устанавливай, все равно нужна синхронизация. 
это верно. а обратное утверждение - не всегда, т.е. если весь код тела процедуры/функции синхронизирован, то это не значит что синхронизирован весь код процедуры

Цитата(Felan @  12.9.2008,  07:44 Найти цитируемый пост)
ниче не понял. По подробнее можно?
задай вопрос конкретнее

Автор: Felan 13.9.2008, 15:17
Цитата(bems @  12.9.2008,  19:13 Найти цитируемый пост)
то что я говорю относиться к внутренним структурам данных менеджера памяти, доступ к которым осуществляется с использованием критической секции, которой влядеет менеджер памяти. 

Ну и я о том же smile

Цитата(bems @  12.9.2008,  19:13 Найти цитируемый пост)
В этом коде действия, подставляемые компилятором после начала процедуры но до первой строки пользовательского кода (и после последней строки но до возврата из процедуры) выполняются вне критической секции пользователя. Значит нужно включить использование критической секции менеджера памяти с помощью IsMultiThread

Полностью согласен.

Цитата(bems @  12.9.2008,  19:13 Найти цитируемый пост)
это верно. а обратное утверждение - не всегда, т.е. если весь код тела процедуры/функции синхронизирован, то это не значит что синхронизирован весь код процедуры

Не понял, как звучит обратное утверждение?

Мне кажется, что мы об одном и том же... Я лично не сталкивался с флагом IsMultiThread, только читал про него. Многопоточные приложения писал и пишу, но пользую TThread, поэтому не думаю об этом флаге.

На вопрос топикастера ты ответил:

Цитата(bems @  10.9.2008,  21:59 Найти цитируемый пост)
для типов не являющихся скрытыми указателями - все нормально, для являющихся - нормально при условии, что IsMultiThread=true

Я утверждаю, что установки этого флага не достаточно. Т.к. этот флаг будет отвечать за выделение памяти под данные из разных потоков, но не за доступ к ним. Доступ к ним надо синхронизировать отдельно.
А в случае топикастера вообще все параллельно. У него данные только в стеке, так что для каждого потока свои будут smile Вот если у него вместо "..." есть код, который работает с "общими" для потоков ресурсами, то тогда в любом случае ему надо делать синхронизацию в ручную.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)