Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2010.03.21;
Скачать: CL | DM;

Вниз

CriticalSection   Найти похожие ветки 

 
Неважно   (2010-01-20 11:56) [0]

Один из потоков увеличивает(Inc) переменную. Второй уменьшает (Dec). А в третьем мне необходимо отдавать значение этой переменной.
С первым и вторым потоком все понятно :

EnterCriticalSection(CS);
Dec(FCountConnect); // или Inc
LeaveCriticalSection(CS);


Собственно, сам вопрос. А в третьем потоке я могу "отдать" значение этой переменной , например, так :

PostMessage(FMainHandle,WM_USER+99,wParam(FCountConnect),0);

Или нужно опять защищать ? Т.е. так :

EnterCriticalSection(CS);
PostMessage(FMainHandle,WM_USER+99,wParam(FCountConnect),0);
LeaveCriticalSection(CS);


Спасибо!


 
@!!ex ©   (2010-01-20 12:10) [1]

Нужно защищать.


 
Ega23 ©   (2010-01-20 12:14) [2]


> Нужно защищать.


На чтение - не нужно.


 
Игорь Шевченко ©   (2010-01-20 12:17) [3]


>
> EnterCriticalSection(CS);
> PostMessage(FMainHandle,WM_USER+99,wParam(FCountConnect),
> 0);
> LeaveCriticalSection(CS);


Так не нужно


 
Б   (2010-01-20 12:17) [4]

Защищать нужно ОБЯЗАТЕЛЬНО в блоках: try..finally.



 EnterCriticalSection(CS);
 Try
    Dec(FCountConnect); // или Inc
 Finally
    LeaveCriticalSection(CS);
 end;



 
Игорь Шевченко ©   (2010-01-20 12:18) [5]

Б   (20.01.10 12:17) [4]

У тебя времени дофига и пальцы стальные ? Ну так не учи других неправильному


 
@!!ex ©   (2010-01-20 12:19) [6]

> [2] Ega23 ©   (20.01.10 12:14)

Другой процесс во время чтения может изменить данные.
Если однопроцессорная система, то пофиг, т.к. операция атомарная(если не ошибаюсь).
Но на многопроцессорных системах данные могут поломаться.
Или я не прав?


 
Б   (2010-01-20 12:20) [7]


> У тебя времени дофига и пальцы стальные ? Ну так не учи
> других неправильному


Какого фига, это не правильно?


 
Игорь Шевченко ©   (2010-01-20 12:23) [8]

Б   (20.01.10 12:20) [7]

Религиозный фанатизм и бездумное написание кода в программировании не уместны.


 
Б   (2010-01-20 12:26) [9]


> Игорь Шевченко ©   (20.01.10 12:23) [8]


Читай справку.


 
Ega23 ©   (2010-01-20 12:27) [10]


> Какого фига, это не правильно?


правильно - когда возможно исключение.


 
Б   (2010-01-20 12:30) [11]


> правильно - когда возможно исключение.


Я написал в целом.


 
Игорь Шевченко ©   (2010-01-20 12:34) [12]

Б   (20.01.10 12:26) [9]

Какое именно место в справке надо читать ?


 
Игорь Шевченко ©   (2010-01-20 12:39) [13]

Ega23 ©   (20.01.10 12:27) [10]

Ты развивай свою мысль дальше, случилось исключение, дальше что ?


 
Неважно   (2010-01-20 12:57) [14]

Спасибо. Что-то тут "шум" возник. Одни говорят не нужно, вторые нужно.
Весело ))

В общем, на чтение защищать не буду.


> Защищать нужно ОБЯЗАТЕЛЬНО в блоках: try..finally.


А какое возможно исключение в коде Inc(FCountConnect) ?


 
Sha ©   (2010-01-20 13:07) [15]

Для изменения проще использовать Interlocked-функции.
Выровненные чтение и запись атомарны, поэтому на чтение защищать не надо.


 
@!!ex ©   (2010-01-20 13:11) [16]

> [15] Sha ©   (20.01.10 13:07)

Атомарные в рамках одного процессора.  Адесли процессы выполняются на разных ядрах?


 
Sha ©   (2010-01-20 13:18) [17]

> Атомарные в рамках одного процессора.  Адесли процессы выполняются на разных ядрах?

По барабану.


 
Anatoly Podgoretsky ©   (2010-01-20 13:38) [18]


> Читай справку.

О ИШ послали RTFM, вот только не по адресу.


 
Anatoly Podgoretsky ©   (2010-01-20 13:40) [19]


> правильно - когда возможно исключение.

Как такое возможно, для процедуры из АПИ, там не то, что исключений, а даже и кода возврата нет, что бы его сгенерировать.


 
Игорь Шевченко ©   (2010-01-20 13:48) [20]

Даже когда возможно исключение, выполнение в finally  LeaveCriticalSection в приводит к довольно трудно диагностируемым ошибкам


 
oxffff ©   (2010-01-20 14:17) [21]


> Sha ©   (20.01.10 13:07) [15]
> Для изменения проще использовать Interlocked-функции.
> Выровненные чтение и запись атомарны, поэтому на чтение
> защищать не надо.


Поддерживаю. Именно такие функции и нужно использовать(c lock префиксом).
Автору смотреть пример Synchronization and Multiprocessor Issues из MSDN.


 
Демо ©   (2010-01-21 12:18) [22]


> Неважно   (20.01.10 11:56) 
> Один из потоков увеличивает(Inc) переменную. Второй уменьшает
> (Dec). А в третьем мне необходимо отдавать значение этой
> переменной.С первым и вторым потоком все понятно :EnterCriticalSection(CS);
> Dec(FCountConnect); // или IncLeaveCriticalSection(CS);


Если у тебя потоки только этим занимаеются - ничего защищать критическими секциями не нужно.


 
Sha ©   (2010-01-21 13:31) [23]

> Демо ©   (21.01.10 12:18) [22]

???
Код давай, как увеличивать/уменьшать.


 
Anatoly Podgoretsky ©   (2010-01-21 14:40) [24]

> Sha  (21.01.2010 13:31:23)  [23]

Такой код только за деньги.


 
Демо ©   (2010-01-21 14:57) [25]

>Sha
inc(value)
dec(value)


 
Sha ©   (2010-01-21 16:23) [26]

> Anatoly Podgoretsky ©   (21.01.10 14:40) [24]
Согласен, возьму, если доплатит.

> Демо ©   (21.01.10 14:57) [25]
Не взлетит.


 
Anatoly Podgoretsky ©   (2010-01-21 17:03) [27]

$79 за дюйм.


 
Демо ©   (2010-01-21 18:43) [28]


> Sha ©   (21.01.10 16:23) [26]


Если больше ничего не нужно от потока, то главное, чтобы исключения не было.
Код выше не должен привести к исключению.


 
Демо ©   (2010-01-21 18:46) [29]

К тому же Inc и Dec с константой генерируются в одну машинную инструкцию...


 
Sha ©   (2010-01-21 19:42) [30]

> Демо

> Если больше ничего не нужно от потока, то главное, чтобы исключения не было.
> Код выше не должен привести к исключению.

Вот код, который точно не приводит к исключению, проблема в том, что он не делает того, что нужно автору.
begin end;

> К тому же Inc и Dec с константой генерируются в одну машинную инструкцию..

 Ну и что.
 Процессор, выполняя ее, должен сначала прочитать значение из памяти, изменить его и затем поместить вычисленное значение в память. Между операциями чтения и записи возможен доступ к памяти со стороны других процессоров, которые также могут попытаться изменить это значение.
 В результате если один процессор инкрементирует в памяти значение 0, а другой декрементирует, мы можем получить любой результат: -1, 0, +1. Как фишка ляжет.


 
Anatoly Podgoretsky ©   (2010-01-21 19:56) [31]


> Если больше ничего не нужно от потока, то главное, чтобы
> исключения не было.

Нужно, нужно что бы работало правильно, а это похоже не атомарная инструкция. Нужно использовать Interlocked функции.


 
Игорь Шевченко ©   (2010-01-21 19:59) [32]

lock xadd :)


 
Sha ©   (2010-01-21 20:07) [33]

или можно короче, если результат не важен:
lock inc


 
Anatoly Podgoretsky ©   (2010-01-21 20:21) [34]

> Sha  (21.01.2010 20:07:33)  [33]

В Дельфи InterlockedIncrement


 
Sha ©   (2010-01-21 20:31) [35]

> Anatoly Podgoretsky ©   (21.01.10 20:21) [34]

InterlockedIncrement реализован через lock xadd


 
Sha ©   (2010-01-21 20:31) [36]

Удалено модератором


 
Anatoly Podgoretsky ©   (2010-01-21 20:41) [37]

> Sha  (21.01.2010 20:31:35)  [35]

Это ассемблерная команда, и нафига тогда ее включать, тем более, что InterlockedIncrement реализован через lock xadd


 
Sha ©   (2010-01-21 21:13) [38]

> Anatoly Podgoretsky ©   (21.01.10 20:41) [37]

Ну, например, lock inc очень часто используется в строковых функция Delphi RTL.


 
Демо ©   (2010-01-21 21:49) [39]


> выполняя ее, должен сначала прочитать значение из памяти,
>  изменить его и затем поместить вычисленное значение в память.
>


Разве так?


 
Sha ©   (2010-01-21 21:52) [40]

> Демо ©   (21.01.10 21:49) [39]

Ага.


 
Демо ©   (2010-01-21 21:52) [41]


> Sha ©


Не буду спорить. Ты прав. Но автору бы почитать сначала что-нибудь.


 
Демо ©   (2010-01-21 21:53) [42]


> Или нужно опять защищать ? Т.е. так :EnterCriticalSection(CS);
> PostMessage(FMainHandle,WM_USER+99,wParam(FCountConnect),
> 0);LeaveCriticalSection(CS);


Вот это совершенно неверная идея. Непонятно что хочет автор.


 
Anatoly Podgoretsky ©   (2010-01-21 22:08) [43]

> Демо  (21.01.2010 21:49:39)  [39]

А как иначе ты предстваляешь?


 
Дмитрий Белькевич   (2010-01-22 00:24) [44]

>А какое возможно исключение в коде Inc(FCountConnect) ?

Исключение, как это не парадоксально, может присутствовать практически в любой строчке кода. Включаем overflow/range checking и получаем замечательное исключение на "ровном" месте. В самый неподходящий момент, само собой.

Так что лучше, если делать именно Dec(FCountConnect), то так и делать:


EnterCriticalSection(CS);
Try
   Dec(FCountConnect); // или Inc
Finally
   LeaveCriticalSection(CS);
end;


Или отказаться от Dec(FCountConnect).

>Даже когда возможно исключение, выполнение в finally  LeaveCriticalSection в приводит к довольно трудно диагностируемым ошибкам

Кгхм, а как же иначе вообще писать? Исключение внутри - и всё - внутрь мы уже никогда больше не зайдём.

Какие ошибки возможны? Я у себя всегда try/finally работу с секциями защищаю. Ни разу пока проблем (именно с try/finally) не было. Повезло, конечно, может.


 
Игорь Шевченко ©   (2010-01-22 00:52) [45]

Дмитрий Белькевич   (22.01.10 00:24) [44]


> Кгхм, а как же иначе вообще писать?


А так и писать, с расчетом на то, что исключение может произойти в любой строке кода.
Вообще, разработка, управляемая исключениями, не так проста, как кажется на первый взгляд.

Секция finally изначально предназначалась для очистки ресурсов, файл закрыть, память освободить, то есть, логика, привносимая в код компилятором, гарантировала выполнение кода в любом случае, как при исключении, так и при нормальном завершении. А что в такой секции обчно делают - освобождают ресурсы во избежание утечки. А вовсе не дать остальным потокам/процессам доступ к несогласованным данным.

Ты вроде с базами общаешься, вот представь, что у тебя есть транзакция из нескольких операторов в таком виде:

try
 insert into foo1 values (bar1,bar2);
 insert into foo2 values (bar3,bar4);
 delete from bazz where bar5 = foo;
finally
 commit
end;

и если произошло исключение во втором или в третьем операторе, данные будут несогласованы.
Ту же самую логику ты закладываешь, вызывая LeaveCriticalSection в finally


> Какие ошибки возможны? Я у себя всегда try/finally работу
> с секциями защищаю. Ни разу пока проблем (именно с try/finally)
> не было. Повезло, конечно, может.


"Очистка после исключения, возбуждённого в коде, владеющим критической секцией, поднимает вопрос: "как вы узнаете, что именно безопасно очищать?". Вы завели критическую секцию для работы с какими-то данными. Критическая секция защищает ваши данные, пока вы изменяете их, т.е. переводите их в некоторое нестабильное состояние и не хотите, чтобы другие видели эти данные в такой несогласованной форме. Но если у вас появляется исключение во время работы внутри критической секции - ну, ваши данные в момент возбуждения исключения находятся в некорректном состоянии. Простой выход из критической секции оставит ваши данные в недопустимом состоянии, которое может привести к более трудно диагностируемым проблемам потом: "как это мой счётчик сумел сбиться?"."

http://transl-gunsmoker.blogspot.com/2008/12/blog-post_7745.html

(процитирован последний абзац)


 
Дмитрий Белькевич   (2010-01-22 02:05) [46]

Спасибо, ясно.

>которое может привести к более трудно диагностируемым проблемам потом

В случае ошибки происходит же не черте-что, а целое исключение. Исключения же try/finally не ловит и не скрывает. И с диагностикой вроде бы никаких проблем.

Тут, конечно, вопрос открытый - стоит ли после исключения разрешать приложению работать или нет. В случае если try/finally не делать - то в секцию больше никто не зайдёт. И приложение окажется полностью или частично неработоспособным. В случае же try/finally есть надежда, что приложение нормально продолжит работу, хотя гарантировать это в общем случае нельзя.


 
Дмитрий С ©   (2010-01-22 05:31) [47]

inc (...) может исключение AV вызвать, разве нет?


 
Anatoly Podgoretsky ©   (2010-01-22 08:57) [48]


> Ну, например, lock inc очень часто используется в строковых
> функция Delphi RTL.

Наверно с целью оптимизации, как inline без лишних движений. Но то что позволено Юпитеру, не позволено быку. Прикладному програмисту лучше стоит двигаться по ровной дороге.


 
Anatoly Podgoretsky ©   (2010-01-22 09:01) [49]


> Игорь Шевченко ©   (22.01.10 00:52) [45]


> try
>  insert into foo1 values (bar1,bar2);
>  insert into foo2 values (bar3,bar4);
>  delete from bazz where bar5 = foo;
> finally
>  commit
> end;

Потому что этот код должен быть иначе и с другой защищеной секцией, стандартная форма обработки транзакций выглядит вот так:
>
try
  insert into foo1 values (bar1,bar2);
  insert into foo2 values (bar3,bar4);
  delete from bazz where bar5 = foo;
  commit;
except
  rollback;
end;


 
Неважно   (2010-01-22 10:37) [50]


>  Ты прав. Но автору бы почитать сначала что-нибудь.


Я то читаю.


> Вот это совершенно неверная идея. Непонятно что хочет автор.


Да иди ты )) Что ж тут непонятного ?


 
Демо ©   (2010-01-22 10:58) [51]


> Да иди ты )) Что ж тут непонятного ?



> PostMessage(FMainHandle,WM_USER+99,wParam(FCountConnect),
> 0);


Непонятно, что ты хочешь сделать в этом коде.


 
Демо ©   (2010-01-22 11:01) [52]


> Anatoly Podgoretsky ©   (21.01.10 22:08) [43]
> > Демо  (21.01.2010 21:49:39)  [39]А как иначе ты предстваляешь?
>


Вроде понял. Автор желает отослать значение в основной поток.
Блин. Что-то 2 дня доходило. Наверное съел чего-нибудь.


 
Игорь Шевченко ©   (2010-01-22 16:48) [53]

Anatoly Podgoretsky ©   (22.01.10 09:01) [49]

Хитрый


 
GanibalLector ©   (2010-01-22 17:55) [54]


> Секция finally изначально предназначалась для очистки ресурсов,
>  файл закрыть, память освободить, то есть, логика, привносимая
> в код компилятором, гарантировала выполнение кода в любом
> случае, как при исключении, так и при нормальном завершении.
>  А что в такой секции обчно делают - освобождают ресурсы
> во избежание утечки. А вовсе не дать остальным потокам/процессам
> доступ к несогласованным данным.


Кстати, в генофонде  обрамляется в try finally.

function CheckSynchronize(Timeout: Integer = 0): Boolean;
var
 SyncProc: PSyncProc;
 LocalSyncList: TList;
begin
 if GetCurrentThreadID <> MainThreadID then
   raise EThread.CreateResFmt(@SCheckSynchronizeError, [GetCurrentThreadID]);
 if Timeout > 0 then
   WaitForSyncEvent(Timeout)
 else
   ResetSyncEvent;
 LocalSyncList := nil;
 EnterCriticalSection(ThreadLock);
 try
   Integer(LocalSyncList) := InterlockedExchange(Integer(SyncList), Integer(LocalSyncList));
   try
     Result := (LocalSyncList <> nil) and (LocalSyncList.Count > 0);
     if Result then
     begin
       while LocalSyncList.Count > 0 do
       begin
         SyncProc := LocalSyncList[0];
         LocalSyncList.Delete(0);
         LeaveCriticalSection(ThreadLock);
         try
           try
             SyncProc.SyncRec.FMethod;
           except
             SyncProc.SyncRec.FSynchronizeException := AcquireExceptionObject;
           end;
         finally
           EnterCriticalSection(ThreadLock);
         end;

         SetEvent(SyncProc.signal);
       end;
     end;
   finally
     LocalSyncList.Free;
   end;
finally
   LeaveCriticalSection(ThreadLock);
 end;

end;


 
Игорь Шевченко ©   (2010-01-22 18:58) [55]

LeaveCriticalSection(ThreadLock);
        try
          try
            SyncProc.SyncRec.FMethod;
          except
            SyncProc.SyncRec.FSynchronizeException := AcquireExceptionObject;
          end;
        finally
          EnterCriticalSection(ThreadLock);
        end;

И нафиг здесь finally ?

function AcquireExceptionObject: Pointer;
asm
       CALL    CurrentException
       OR      EAX, EAX
       JE      @@Error
       INC     [EAX].TRaisedException.RefCount
       MOV     EAX, [EAX].TRaisedException.ExceptObject
       RET
@@Error:
       { This happens if there is no exception pending }
       JMP     _Run0Error
end;

Я не вижу причины для исключения в функции AcquireExceptionObject, текущий Exception наличествует, так как вызов идет из секции except,

функции

function CurrentException: PRaisedException;
asm
       CALL    SysInit.@GetTLS
       LEA     EDX, [EAX].ExceptionObjects
       MOV     EAX, [EAX].ExceptionObjectCount
       OR      EAX, EAX
       JE      @@Done
       DEC     EAX
       IMUL    EAX, TRAISEDEXCEPTION_SIZE
       ADD     EAX, EDX
       JMP     @@Exit
@@Done:
       CALL    SysInit.@GetTLS
       MOV     EAX,[EAX].ExceptionList
@@Exit:
end;

вроде тоже на первый взгляд негде возбуждать исключение



Страницы: 1 2 вся ветка

Текущий архив: 2010.03.21;
Скачать: CL | DM;

Наверх




Память: 0.62 MB
Время: 0.015 c
2-1263562192
fford
2010-01-15 16:29
2010.03.21
вызов функции из потока


2-1263543792
tonich
2010-01-15 11:23
2010.03.21
USB


2-1263843087
novichek
2010-01-18 22:31
2010.03.21
canvas.textWidth для разных стилей


1-1242222408
Гарик
2009-05-13 17:46
2010.03.21
Справка WinHelp в Дельфи 7


2-1263898004
виктор
2010-01-19 13:46
2010.03.21
Как изменить свойство группы компонентов?