![]() |
|
Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply |
![]()
|
|
| pethead |
|
|||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 101 Регистрация: 13.11.2007 Репутация: нет Всего: нет |
задача: есть 10000 объектов-классов котрые каждый в своем треде может иметь доступ к общей переменной. доступ каждого синхронизирован любым доступным методом (крит. секция, мютекс, семафор)т.е коллизий нет. но... надо чтобы все потоки работали с переменной каждый 1 раз пока все 10000 объектов не изменят эту переменную. я так понял что не предпринять мер то объекты будут допускаться к переменной по усмотрению планировщика вин32 т.е несколько случайно и не по разу а некоторые объекты могут и не дотронуться до переменной. так?
как вариант после доступа потока к переменной останавливать поток доступа к ней, выставлять в другой общей переменной счетчик +1 и запускать другой поток который будет смотреть на счетчик и ждать пока тот не станет равным 10000 т.е. все потоки обработали переменную и теперь можно возобновлять поток доступа и останавливать поток счетчика, при этом обнулив счетчик... мда... если не выйдет то придется тупо организовывать в один поток все и в нем по циклу перебирая допускать всех объектов к переменной, но уже не самостоятельным потоком (или потоком все таки? но теперь хоть будет упорядоченно), а просто обычным методом. Это сообщение отредактировал(а) pethead - 2.10.2008, 17:31 |
|||
|
||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 16 Всего: 89 |
Ээээ.... этак у вас получается 10к потоков? Вы явно что-то не то делаете. Обычно не имеет смысла делать потоков больше, чем число процессоров (с учётом ядер) или для разделения GUI/работы, ввода-вывода, клиентских подключений в службах и т.п. Такого быть не может. Добавлено через 5 минут и 16 секунд Ссылка по теме: Does Windows have a limit of 2000 threads per process? -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Если поток "вызвал ждущую" функцию с конечным интервалом, то, imho, возможно. "Тут возникает интересный вопрос. Если несколько потоков ждет один объект ядра, какой из них пробудится при освобождении этого объекта? Официально Microsoft отвечает на этот вопрос так: «Алгоритм действует честно" Что это за алгоритм, Micro soft не говорит, потому что нс хочст связывать себя обязательствами всегда придер живаться именно этого алгоритма. Она утверждает лишь одно- если объект ожидает ся несколькими потоками, то всякий раз, когда этот объект переходит в свободное состояние, каждый из них получает шанс на пробуждение. Таким образом, приоритет потока не имеет значения- поток с самым высоким приоритетом не обязательно первым захватит объект. Не получает преимущества и поток, который ждал дольше всех. Есть даже вероятность, что какой-то поток сумеет повторно захватить объект. Конечно, это было бы нечестно по отношению к другим потокам, и алгоритм пытается не допустить этого. Но никаких гарантий нет." (с) Jeffrey Richter Т.е. если мы ожидаем не INFINITE-ое время, то можем и не добраться |
|||
|
||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 16 Всего: 89 |
Ну это очевидно -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Ну, это кому как. Просто, раз уж речь зашла об "упорядоченной синхронизации", то я сочла уместным показать к каким выводам можно прийти, оприраясь на Рихтера. А именно: Допустим у нас есть два потока. Пусть каждый из них ожидает объекта синхронизации, захватывает ресурс, удерживает его в течении 1 милисекудны, отдает и снова входит в режим ожидания. И пусть у первго потока приоритет TimeCritical, а у второго Idle. Мы их запускаем и ждем, допустим, на час ( или два Если утверждение Рихтера истинно, то существует отличная от нуля вероятность, что первый поток (который TimeCritical) так ни разу и не захватит объект. Например, для меня, этот факт не является "ну уж соль очевидным" А выводы из этого можно сделать довольно плачевные. Варианты типа зашли в ресурс и увидев, что мы здесь раньше чем надо, быстренко вышли - не прокатывает |
|||
|
||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 16 Всего: 89 |
Не торопись Конкретно в твоём примере это не так (вообще в любом разумном сценарии с двумя потоками это невозможно). Два потока. Поток с низким приоритетом захватил ресурс. Поток с высоким приоритетом пытается захватить ресурс и ждёт поток с низким. Поток с низким приоритетом после вашей обещанной 1 милисекудны отпускает ресурс. Кто его тут же получает? Поток с высоким приоритетом! Чтобы поток с высоким приоритетом не получил ресурс, необходимо чтобы вместе с ним этот ресурс ждал бы ещё третий поток. Да. Но эта вероятность исчезающе мала. Теоретически - да, это возможно, но на практике - маловероятно. С вероятностями нужно аккуратно. Вон, есть же вероятность, что ваш свеже сгенеренный GUID совпадёт ещё с чьим-то. Но, ничего, обходимся же как-то Утверждение Рихтера как раз таки гарантирует невозможность (практическую!) сценария, при котором поток не получит ресурс. Не надо только сводить всё к крайностям - очевидно, что если у вас 11 потоков, каждый из которых работает над ресурсом 1 секунду, а ресурс ждёт не более 10 секунд, то гарантировано будет как минимум 1 поток, который не успел поработать над ресурсом (именно поэтому, я сказал, что для ограниченного времени ожидания этот факт очевиден). Алгоритм системы как раз все свои силы направляет на предотвращение ситуации, когда поток не получит ресурса. Гарантий нет, да. Но и с GUID нет гарантий уникальности. Но вся его сущность направлена на обеспечение этой уникальности. Это сообщение отредактировал(а) CodeMonkey - 3.10.2008, 08:42 -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 16 Всего: 89 |
Смотри, даже если взять твой сценарий с двумя потоками.
Нет гарантий, что поток будет держать ресурс 1 милисекуду! Вот их уже действительно нет. Поток может быть вытеснен вообще другим процессом с высоким приоритетом. Машина вообще может в спячку уйти. Много, много чего может случиться. Что же мы получим? Поток с низким приоритетом захватил ресурс, поток с высоким начинает его ждать (положим минуту, ну пять минут максимум). В это время в обработке ресурса у первого потока происходит задержка (машина ушла в спячку). Значит, поток с высоким приоритетом за всё своё время не успеет ни разу потрогать ресурс. Ваш простейший сценарий. Два потока. А диспетчер, который отвечает за пробуждение потоков, даже не получил шанса проявить себя, т.к. второй поток вылетел по таймауту раньше, чем первый отпустил ресурс! Вот ещё одно доказательство очевидности вышеуказанного факта для случая с конечным ожиданием ресурса P.S. Конечно, этот сценарий опять-таки маловероятен, но он просто иллюстрирует:
-------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| Riply |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Угу, согласна, в сценарий надо добавить третий поток - заглушку. Не "исчезающе мала", а "отлична от нуля" - это совсем разные вещи
Так и пример у нас надуманный, а на практике мы имеем: "10000 объектов-классов котрые каждый в своем треде может иметь доступ к общей переменной" А если серьезно, то я хотела сказать что при необходимости "упорядоченной синхронизации" разумного числа потоков варианты типа "заскочил - проверил - вышел" не годятся. Хороший пример, понравился. P.S. Ну вот видишь, как дела обстоят, а ты "очевидно, да очевидно" На тему этого "очевидно", приведу цитату из "Физики продолжают шутить": "В подобных случаях читатель, пытаясь самостоятельно сделать тот шаг, который автору представлялся очевидным, чаще всего оказывается в положении студентов на одной лекции по математике, о которой я недавно читала. Профессор, стоя у доски, был погружен в длиннейший вывод. В каком-то месте он произнес стандартную фразу «отсюда с очевидностью вытекает Следующее» и написал длинное и сложное выражение, абсолютно не похожее ни на что из написанного ранее. Затем он заколебался, на его лице появилось озадаченное выражение, он что-то пробормотал и прошел из аудитории в свой кабинет. Появившись оттуда через полчаса, он с довольным видом объяснил аудитории: «Я был прав. Это, действительно, совершенно очевидно». " |
||||
|
|||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 16 Всего: 89 |
Да, это я понял ;) И согласен, что не годятся. Но не по этой причине Потому что в данном случае будет использоваться бесконечное ожидание. Смысл делать его конечным? Чтобы пользователь не ждал, если работа займёт значительное время? Не уверен, что это имеет значение в этом сценарии, но даже так - мы просто выйдем по таймауту и будет всё чинно и штатно. А не годится это по той причине, что потоки будут постоянно дёргать счётчик. Это называется pooling, который плох по определению Более того, как я уже сказал, плох и сам подход. Потоков больше 10 - это уже повод задуматься, а больше 200 - явный пример неправильно спроектированной программы. Ок, это зависит от способа интерпретации слов Рихтера -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
||||
|
||||
| Romikgy |
|
|||
![]() Любитель-программер ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7326 Регистрация: 11.5.2005 Где: Porto Franco Odes sa Репутация: 13 Всего: 146 |
А не лучше ли (при поставленой задаче автора) создать Н-ное число эвантов, и поочереди их активировать , и в потоке после синхронизации отключать активацию что будет поводом (для манагера потоков ) об активации следующего потока
-------------------- Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. |
|||
|
||||
| Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Если кому интересно... CS Vista |
|||
|
||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 16 Всего: 89 |
Во, отличная ссылка! Демонстрирует, что мы не должны опираться на алгоритм планировщика. Довольно удивительное поведение. Удивительно оно в первую очередь тем, что встречается на двухядерной системе.
Ключевым компонентом здесь является немедленный захват ресурса после его освобождения: т.е. LeaveCriticalSection(CS); EnterCriticalSection(CS); Действительно, на однопроцессорной машине после LeaveCriticalSection первый поток вполне может не исчерпать свой квант времени и продолжит выполнение, вызывая EnterCriticalSection (*). Поэтому на однопроцессорной машине такое поведение не было бы удивительным. Удивительно, что оно проявляется именно на двухядерной машине. По идее, когда первый поток выходит из LeaveCriticalSection, событие будет в сигнальном состоянии. Это значит, что второй поток немедленно пробуждается (у нас же свободно второе ядро) прямо во время вызова LeaveCriticalSection. Как, интересно, система определяет, что его нужно придержать? P.S. (*) На самом деле, даже на однопроцессорной машине это не так. См. например: http://forum.sources.ru/index.php?showtopi...t&p=2095611
Да, как-то на эти слова я не обратил внимания. Я подразумевал что между освобождением и захватом ресурса поток ещё что-то делает. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| Virtuals |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 476 Регистрация: 27.11.2006 Репутация: 4 Всего: 11 |
хм а почему бы не использовать, флаговую переменную, где все потоки и будут отмечатся, как только отработают с данными.
используя функции InterlockedXXX (Защищенный доступ к переменным (Interlocked Variable Access) ) там вроде для чтения блокировка не требуется а если еще добавить поток, менеджер, который будет выставлять флаг "кому можно получать доступ" /только он туда имеет право писать, остальные только читают/ то вообще влегкую реализовать любой мыслимый порядок доступа Это сообщение отредактировал(а) Virtuals - 26.10.2008, 19:28 |
|||
|
||||
![]()
|
| Правила форума "Delphi: WinAPI и системное программирование" | |
|
|
Запрещено: 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |