Форум: "Прочее";
Текущий архив: 2008.04.20;
Скачать: [xml.tar.bz2];
ВнизПодсчет количества вхождений потоков Найти похожие ветки
← →
ага (2008-03-04 20:51) [40]ЗЫ
> if CoreCounterThread = 0 then
Эт так, мелочь. По сравнинию с остальным.
← →
ага (2008-03-04 20:52) [41]Тьфу ты, эту имел в виду
> if CoreCounterThread = 1 then
← →
ЦУП © (2008-03-05 01:06) [42]
> ага (04.03.08 19:42) [35]
> Фигней страдаешь. Сначала нать завершить потоки, потом из
> майн валить ядро. Ну а так
> ага (04.03.08 19:45) [36]
> Не, так:
> ага (04.03.08 20:51) [40]
> ЗЫ> if CoreCounterThread = 0 thenЭт так, мелочь. По сравнинию
> с остальным.
> ага (04.03.08 20:52) [41]
> Тьфу ты, эту имел в виду> if CoreCounterThread = 1 then
Ты сам определись сначала, а потом советуй что-то.
← →
Пробегал... (2008-03-05 01:13) [43]ага (04.03.08 20:29) [38]
Ню-ню. Сразу чуйствуется - специалист!
код:while InterLockedCompareExcenge(CoreClients, 0, 0) <> 0 do Sleep(0);
плох тем, что пока будет ждать установления нуля - загрузит процессор (или по-крайней мере одно ядро процессора) на 100%. То есть, такой примитивный цикл будет кушать очень много вычислительных ресурсов и притормаживать другие потока такого же или не дай бог меньшего приоритета.
Также InterlockedCompareExchange существует только под Windows NT, а моя программа расчитана на работу во всей линейке win9x / winNT
А чем мой код плох?
ага (04.03.08 20:52) [41]
> if CoreCounterThread = 1 then
и что тебе не нравится? Первый зашедший поток очищает событие и пока CoreCounterThread опять не станет нулем - событие не произойдет. Можно было написать:if CoreCounterThread > 0 then
но по смыслу получится тоже самое, просто зачем каждый раз сбрасывать событие.
Не понял, что не так, все будет работать на ура. Более того, уже работает.
← →
ага (2008-03-05 04:00) [44]2 ЦУП
Вот как раз тя забыл спросить, че мне делать сначала, а че потом. Всех спросил, а тя забыл.
2 Проходил
Да, загрузит. А чем загрузит-то? Работой потоков в ядре. Это будет самая быстрая реакция на выход всех потков из твово ядра. И он применим там, где применим. Приоритеты? А ты че, сам не знаешь какие у тя приоритеты потоков? Разные - не используй Sleep(0). Другое ограничение - ежель потоки в ядре будут че-нитьб ждать. Эт че, все нать разжевывать? Самому не дотумкаться, что показан принцип, а не готовый код.
А правильное решение я те уж сказал - первой же строкой.
> Не понял, что не так, все будет работать на ура. Более того,
> уже работает.
Ага, будет, как же. Расскажи эт своей бабушке. Ладно, я с утра добрый.
Вот у тя поток T1 вызвал ThreadSafeEnter. Выполняется:
coreCriticalSection.Enter ;
try
if CoreFlagRun then
begin
Тут его прерывает система и начинает работать поток T2, котрый вызыват деструктор ядра:
> Ну и в деструкторе просто выставляется флаг, после чего
> ожидается наступление события coreEvent
CoreFlagRun:= false;
WaitForSingleObject(coreEvent...
В каком состоянии будет coreEvent? Догадайся с трех раз. Эт если потоки переключаются. А ежель на многопроцессорной тачке, то те же гонки, вид сбоку, тока вероятность еще выше.
Дыра, и когда ты в нее попадешь - вопрос времени. А то что попадешь - к бабкам не ходи.
← →
Семеныч (2008-03-05 06:30) [45]1. В ядре создаем ThreadList и делаем его доступным всем потокам.
2. Каждый поток имеет FreeOnTerminate = True.
3. Каждый поток имеет такой Execute:
procedure TMyThread.Execute;
begin
ThreadList.Add(Self);
try
DoWork;
finally
ThreadList.Remove(Self);
end;
end;
4. Завершение работы:
а). если метод DoWork потоков проверяет свойство Terminated, то сначала ядро приказывает всем потокам завершиться:
with ThreadList, LockList do
try
for i := 0 to Count - 1 do
TMyThread(Items[i]).Terminate;
finally
UnlockList;
end;
Этот код безопасен, потому что перед его выполнением ядро залочило список. Поэтому при выполнении этого кода ни один поток завершиться не сможет (так как будет ждать, пока ядро не освободит список) - значит, Count не изменится.
Если метод DoWork потоков свойство Terminated не проверяет, то этот код не нужен (хотя и не помешает).
б). ядро ждет, пока не завершатся все потоки:
with ThreadList, LockList do
while Count > 0 do
begin
UnlockList;
Sleep(1);
end;
Этот код тоже безопасен (по тем же соображениям) и тратит минимум процессорного времени.
в). ядро завершает свою работу - уже обычным образом и без всяких фокусов.
А доступ потоков к функциям ядра даже и запрещать не надо. Тем более, что не каждый алгоритм можно прерывать на полпути.
← →
Семеныч (2008-03-05 06:42) [46]Сорьки, в п. б) фигню написал. Ждать завершения всех потоков надо так:
while True do
begin
with ThreadList, LockList do
try
if Count = 0 do
Break;
finally
UnlockList;
end;
Sleep(1);
end;
← →
Пробегал... (2008-03-05 08:38) [47]ага (05.03.08 4:00) [44]
Да, загрузит. А чем загрузит-то?
бесконечным вычислением значения количества потоков
ага (05.03.08 4:00) [44]
Это будет самая быстрая реакция на выход всех потков из твово ядра
ну конечно. Быстрее специального механизма синхронизации, встроенного в windows? ;)
К тому же, забрав на себя полностью ресурсы процессора этот поток нефигово притормозит другие потоки.
ага (05.03.08 4:00) [44]
Приоритеты? А ты че, сам не знаешь какие у тя приоритеты потоков?
а причем здесь мои потоки даже? Такой код затормозит и другие потоки в системе, особенно имеющие приоритет ниже или равный потоку, который финализирует ядро.
ага (05.03.08 4:00) [44]
Разные - не используй Sleep(0).
я и не использую ;)
ага (05.03.08 4:00) [44]
Ага, будет, как же. Расскажи эт своей бабушке. Ладно, я с утра добрый.
Вот у тя поток T1 вызвал ThreadSafeEnter. Выполняется:
coreCriticalSection.Enter ;
try
if CoreFlagRun then
begin
Тут его прерывает система и начинает работать поток T2, котрый вызыват деструктор ядра:
> Ну и в деструкторе просто выставляется флаг, после чего
> ожидается наступление события coreEvent
CoreFlagRun:= false;
WaitForSingleObject(coreEvent...
В каком состоянии будет coreEvent? Догадайся с трех раз
эх... ну ладно, я не привел код деструктора, думал это очевидно. Код на самом деле такой:coreCriticalSection.Enter ;
try
CoreFlagRun := false ;
finally
coreCriticalSection.Leave ;
end;
WaitForSingleObject(coreEvent, INFINITE) ;
теперь подумай и догадывайся хоть с 10 раз.
ага (05.03.08 4:00) [44]
А то что попадешь - к бабкам не ходи
забавно. Придумать самому хреновый код и на этом основании уверять, что попадешь в дыру ;) Ну если как ты написал - действительно, попадешь ;)
← →
Пробегал... (2008-03-05 08:49) [48]Семеныч (05.03.08 6:30) [45]
согласен, хорошо. Мне не подходит, потому что функции ядра могут вызывать не только мои потоки, но и чужие из других DLL.
У тебя основа на том, что никто не будет дергать функции ядра, когда все потоки умрут. А ядро не завершится, пока все потоки не умрут. У меня немного не так, к сожалению ;(
Может возникнуть ситуация, что все потоки умрут, а кто-то извне дернет метод ядра. Конечно, я по максимуму сократил такой вариант развития событий - и библиотеки по идее должны быть выгружены к тому времени, и ссылка на ядро обнуляется до начала процесса финализации, то есть типа:LocalCore := Core ;
Core := nil ;
FreeAndNil(LocalCore);
при этом у экспортных функций есть проверка аля:function lalala: boolean; stdcall;
begin
if Assigned(Core) then
Result := Core.nanana
else
Result := false ;
end;
но все равно... оставлю свой вариант на всякий случай ;)
← →
Игорь Шевченко © (2008-03-05 10:17) [49]Вот как же винда, зараза, объекты удаляет, когда в них больше нужды нету...Откуда она знает, не иначе, внутри шаман сидит. И ей пофиг, винде, на каких языках код потоков написан. И критических секций с семафорами она не использует, потому как накладно и рекурсия.
Но работает ведь. Зараза.
← →
Пробегал... (2008-03-05 11:52) [50]Игорь Шевченко © (05.03.08 10:17) [49]
Вот как же винда, зараза, объекты удаляет, когда в них больше нужды нету..
я думаю она работает по принципу описанным Семеныч в [45]. То есть, ядро системы работает всегда, пока существуют какие-то процессы. Процессы существуют пока существуют потоки.
На этапе финализации винда в любом случае убивает все потоки и все процессы внешние. После этого есть гарантия, что никто больше не вызовет функции ядра (а кому их вызывать?) - после чего освобождаются все ресурсы занятые в процессе работы ядра без страха что в это время кто-то дернет метод ядра.
Я думаю так.
Но я уже писал, что мне это не совсем подходит... Хотя конечно можно и так делать, в любом случае так или иначе убивать все потоки имеющие доступ к экземпляру ядра, а остальные варианты вызовов методы ядра исключить...
← →
Игорь Шевченко © (2008-03-05 12:08) [51]Пробегал... (05.03.08 11:52) [50]
"Вошел поток в метод - на счетчике плюс 1, вышел из метода - минус один. Соответственно, при уничтожении ядра делаю так: запрещаю новые вхождения в методы ядра, после чего ожидаю когда счетчик опуститься в ноль - это означает, что все потоки отработали на ядре. Вроде бы логично."
Вот-вот. Винда тоже самое делает с объектами, пока кто-то их использует - хрен они удалятся из системы. Это к [49]
← →
Пробегал... (2008-03-05 13:07) [52]Игорь Шевченко © (05.03.08 12:08) [51]
вы к тому, что InterlockedIncreament работает куда быстрее, чем аля:cs.Enter
try
inc(Counter);
finally
cs.Leave;
end;
?
← →
Игорь Шевченко © (2008-03-05 13:08) [53]
> вы к тому, что InterlockedIncreament работает куда быстрее,
> чем аля:
не то слово
← →
Пробегал... (2008-03-05 13:11) [54]просто смысла нет использовать в моем варианте. У меня ожидания по WaitForSingleObject от события. Событие все равно должно выставляться в критической секции. А тогда уже не имеет смысл использовать Interlocked.
Это надо переделать логику - точно убивать все потоки и не допускать возможности новых вызовов методов ядра. Тогда да, от WaitForSingleObject и от события можно уйти, а для счетчика использовать Interlocked...
← →
Игорь Шевченко © (2008-03-05 13:16) [55][31]
← →
Пробегал... (2008-03-06 02:16) [56]ну ладно, вот и поговорили ;)
← →
имя (2008-03-06 03:40) [57]Удалено модератором
← →
Пробегал... (2008-03-06 19:13) [58]а что лучше использовать для синхронизации доступа к потокам - критические секции или эвенты? У меня отложилось в памяти, что критич. секции самое быстрое из средств синхронизации. По крайней мере в некоторых случаях, хотя в других они могут приводить к созданию мьютекса (вроде Рихтер, не помню почему).
То есть, крит. секция с ее Enter / Leave, или WaitForSingleObject на событии лучше? Когда первый вошедший поток сбрасывает событие, а после завершения работы выставляет.
← →
Palladin © (2008-03-06 19:40) [59]Да можешь и события использовать... они идейно не для этого сделаны, да и к тому"же нужно иметь ввиду что один поток может два раза сделать Enter в одну и туже критическую секцию, а вот два раза "войти" в событие у тебя не получится :)
← →
Пробегал... (2008-03-06 20:03) [60]Palladin © (06.03.08 19:40) [59]
Да можешь и события использовать
да я понимаю что могу. Просто интересно стало что быстрее работает.
← →
ЦУП © (2008-03-06 20:10) [61]
> Пробегал... (06.03.08 20:03) [60]
> Palladin © (06.03.08 19:40) [59]
> Да можешь и события использовать
>
> да я понимаю что могу. Просто интересно стало что быстрее
> работает.
Быстрее любые другие объекты кроме критических секций.
На них расходуется в сотни раз больше тактов процессора.
← →
Пробегал... (2008-03-06 20:24) [62]ЦУП © (06.03.08 20:10) [61]
любые другие объекты синхронизации? Ничего не понял, ты хочешь сказать, что критические секции самый медленынй способ синхронизации?! Медленне мьютекса, семафоров и прочее?!?! Я был совершенно другого мнения
← →
ЦУП © (2008-03-06 20:31) [63]
> Пробегал... (06.03.08 20:24) [62]
> ЦУП © (06.03.08 20:10) [61]
>
> любые другие объекты синхронизации? Ничего не понял, ты
> хочешь сказать, что критические секции самый медленынй способ
> синхронизации?! Медленне мьютекса, семафоров и прочее?!?
> ! Я был совершенно другого мнения
Точно! Сейчас аргументированно не могу доказать, но после изучения в прошлом этой проблемы отложилось именно это.
← →
Loginov Dmitry © (2008-03-06 21:03) [64]> Быстрее любые другие объекты кроме критических секций.
У Рихтера есть объяснение механизма работы критической секции. Из него следует, это это - самый быстрый способ блокировки.
← →
Пробегал... (2008-03-06 22:03) [65]таки перечитал Рихтера ;)
Критич. секция уводит исполнения в режим ядра, переход в который и является очень медленным.
WaitForSingleObject делает то тоже самое, видимо. Поэтому с этой точки зрения пофигу практически.
Просто притические секции могут применять спин. блокировку, то есть проверку-sleep-проверку-sleep, и так заданное количество раз, только после этого уже переход в режим ядра и заморозка потока. Кстати, с этой точки зрения судя по всему Suspend и Resume тоже не самые быстрые операции.
Но установку количества проверок критической секцией условий блокировки перед уходом в режим ядра делается функцией http://msdn2.microsoft.com/en-us/library/ms686197.aspx - а она введена только начиная с w2k. И пригодна только для многопроцессорных машин.
А так видимо разницы нет.
← →
Пробегал... (2008-03-06 22:08) [66]я одного там не понял - почему пригодно только для многопроцессорной машины? Рихтер как объясняет - мол, на однопроцессорной спин разблокировки просто не может быть. Типа тот поток не сможет освободить ресурс, пока этот поток делает цикл проверку-sleep-проверку-sleep.
Но почему во время этой проверки не может быть такого, что у этого потока управление отнимут, оно перейдет к тому потому, который освободит ресурс, а когда управление вернется к этому потоку проверка уже не сработает, произойдет вход в критическую секцию без выхода на режим ядра и засыпания.
← →
Пробегал... (2008-03-06 22:10) [67]ЦУП © (06.03.08 20:31) [63]
Точно! Сейчас аргументированно не могу доказать, но после изучения в прошлом этой проблемы отложилось именно это
ну в принципе ты прав, если происходит выход в режим ядра - то там делается что-то типа аналогичному WaitForSingleObject над тем же мьютексом, привязанным к критической секции. Поэтому "чистое" использование мьютекса может быть и быстрее. Но не на много.
Исключение - это та самая спин-блокировка на многопроцессорной тачке, там критическая секция может отработать быстрее.
← →
Пробегал2... (2008-03-09 03:50) [68]я одного там не понял - почему пригодно только для многопроцессорной машины? Рихтер как объясняет - мол, на однопроцессорной спин разблокировки просто не может быть. Типа тот поток не сможет освободить ресурс, пока этот поток делает цикл проверку-sleep-проверку-sleep.
Но почему во время этой проверки не может быть такого, что у этого потока управление отнимут, оно перейдет к тому потому, который освободит ресурс, а когда управление вернется к этому потоку проверка уже не сработает, произойдет вход в критическую секцию без выхода на режим ядра и засыпания.
← →
Пробегал2... (2008-03-09 04:34) [69]"Вошел поток в метод - на счетчике плюс 1, вышел из метода - минус один. Соответственно, при уничтожении ядра делаю так: запрещаю новые вхождения в методы ядра, после чего ожидаю когда счетчик опуститься в ноль - это означает, что все потоки отработали на ядре. Вроде бы логично."
Вот-вот. Винда тоже самое делает с объектами
Хотя это ИШ ссылался на мои слова, все равно это ненадежный алгоритм работы. Итак, идет финализация ядра.
Допустим, мы запретили новые вхождение в методы ядра.
В каждом методе ядра при входе идет InterlockedIncreament счетчика, по выходу из метода - InterLockedDecreament.
В финализации ядра мы типа ждем когда счетчик станет равным нулю.
Но тут есть и минусы, и баги:
1) некий поток может войти в метод ядра, но не успет вызвать InterlockedInreament. Тогда в финале ядра счетчик будет равен 0, ядро подумает что потоков внутри него не осталось и финализация пойдет дальще. А в это время тот неуспевший поток сделает InterlockedIncreament и продолжив работу, приведя к непредсказуемым последствиям.
2) каким образом контролировать, что счетчик в ноль ушел? Аля:
while Counter <> 0 do sleep(1);
? Не сильно ли это загрузит процессор, мешая другим потоком работать (в том числе совершать последние финальные действия).
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2008.04.20;
Скачать: [xml.tar.bz2];
Память: 0.62 MB
Время: 0.039 c