Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2010.03.21;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх





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


6-1214837103
Валентин
2008-06-30 18:45
2010.03.21
Эмуляция DHCP


2-1263550088
lexii
2010-01-15 13:08
2010.03.21
Перенос значений переменных из одного Unit на доугой


2-1263711881
MK26
2010-01-17 10:04
2010.03.21
Помогите установить пароль на готовую уже программу (exe фаил)


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





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский