Про интервью в Майкрософт... - new branch
-
- Уже с Приветом
- Posts: 4468
- Joined: 21 Sep 2000 09:01
- Location: Sammamish, WA
Про интервью в Майкрософт... - new branch
Начало здесь: http://forum.privet.com/viewtopic.php?t=21442&start=80
__Vlad__, а я думал Вы сами и откроете тему - ну да ладно, будем считать, что за Вами должок .
[quote:f28ebcc725]Т.е. насколько я понял "правильная" синхронизация заключается в захвате spinlock перед обращением к С runtime и немедленном его освобождении сразу же после возвращения управления вызывающей процедуре. А вот если подержать spinlock еще чуть-чуть и прочитать errno в локальную переменную, это уже вырожденный случай …[/quote:f28ebcc725]
Захват спинлока перед вызовом runtime функции (да, речь шла и идёт о single-threaded варианте) и освобождение его после того как errno скопирована в локальную переменную – это конечно поможет, но только что Вы будете делать с глобальным переменными библиотеки, которые влияют на выполнение последующих вызовов? Будете перед вызовом восстанавливать локальный для потока контекст библиотеки (после захвата спинлока и перед каждым вызовом каждой библиотечной функции, которая не является stateless) и сохранять его каждый раз после окончания вызова (и до освобождения спинлока)?
А что Вы будете делать с той частью контекста, которая Вам не доступна или о котором Вам вообще ничего неизвестно (если Вы, конечно, не являетесь автором библиотеки)? В результате всё и закончится тем самым вырожденным случаем (или его вариацией) - ничего лучше в таких условиях сделать нельзя.
[quote:f28ebcc725]Если не изобретать своей собственной классификации, то в общепринятой есть понятие high thread affinity, т.е. объект/библиотека привязаны к одному потоку и вызов из других потоков не гарантирует правильную работу. Существует масса примеров high thread affinity (STA COM object, окно и т.д.). [/quote:f28ebcc725]
Приходится изобретать, так как устойчивой "общепринятой" не существует. Да и потом, это совсем и не моё изобретение (а жаль ). Что касается thread affinity и всего что с этим связано – это терминология и, соответственно, классификация принятая преимущественно в COM. Посмотрите в гугле – поиск по (“thread affinity”) или (“thread affinity” COM) даёт одни и те же результаты.
[quote:f28ebcc725]Кроме того есть понятие thread unsafe - от пользователя требуется некоторый набор телодвижений чтобы все работало. Требования могут быть разные, от просто блокировки одновременных обращений, до требования использовать конкретный поток для любых обращений. [/quote:f28ebcc725]
Ваше определение thread-unsafe включает high thread affinity ("требования использовать конкретный поток для любых обращений"). Что только ещё один аргумент за то, что такая классификация шире, чем нужно. Слишком много разного между single-threaded и thread-safe вмещается. А тот случай, о котором шла речь как о thread-neutral - просто очень важен практически: Вам гарантируется, что при соблюдении неких несложных правил Вы получите максимально возможный concurrency.
Попробую на примере STL ещё раз пояснить, что попадает в эту категорию: до тех пор пока разные потоки не работают с одними и теми же экземплярами объектов, доступных пользователю, никаких проблем нет. В противном случае пользователь защищает доступные ему им объекты (как созданные им, так и те, которые уже есть в библиотеке, скажем std::cout) сам. О минимально необходимой но достаточной синхронизации доступа к внутренним объектам, недоступных пользователю (и только о них - ни о чём больше) библиотека позаботится сама - это гарантируется. В общем, подход в духе Эйнштейна: "as simple as possible, but not simpler".
[quote:f28ebcc725]Т.е. предположим, что поток A занимается сложной обработкой и вначале захватил mutex, после чего заснул на некоторое время. Тут от пользователя пришел короткий запрос, который требует захвата того же mutex. Т.к. thread B не может захватить этот mutex он засыпает. Имеем два thread-a которые оба спят, пользователь ждет. Через некоторое время просыпается А делает часть работы и опять засыпает. Thread B все равно ждет.[/quote:f28ebcc725]
Wrong. Речь шла не о "засыпать": добровольно отдать CPU отнюдь не то же самое, что "разбуди меня через столько-то миллисекунд". Поэтому в этой ситуации, диспетчер сразу вернёт CPU потоку А - это же ясно из исходного текста: "если все ждут того самого ресурса, то они и не буду претендовать на CPU".
[quote:f28ebcc725]В конечном итоге, вместо того чтобы пользователь получил ответ, что запрошенный ресурс недоступен, он прождет все время, пока обрабатывается сложный запрос.[/quote:f28ebcc725]
Этого как раз и пытаются избегать, бедному пользователю обычно таких страшных вещей не сообщают . Наоборот, TP системы, как правило, сами "разводят" конфликтующие по ресурсам транзакции. Можно, конечно, немедленно (или после конфигурируемого timeout) прекратить транзакцию, которой не повезло нарваться на ожидание, но это имеет обычно смысл только в каких-то специальных случаях.
Что касается вообще техник синхронизации и диспетчеризации в тех же системах обработки транзакций – если Вы хотите больше подробностей или если Вам что-то кажется нелогичным или неправильным – можно, конечно, поговорить подробнее, но это слишком большая тема. Есть масса толковых статей и книг, где это всё можно найти.
__Vlad__, а я думал Вы сами и откроете тему - ну да ладно, будем считать, что за Вами должок .
[quote:f28ebcc725]Т.е. насколько я понял "правильная" синхронизация заключается в захвате spinlock перед обращением к С runtime и немедленном его освобождении сразу же после возвращения управления вызывающей процедуре. А вот если подержать spinlock еще чуть-чуть и прочитать errno в локальную переменную, это уже вырожденный случай …[/quote:f28ebcc725]
Захват спинлока перед вызовом runtime функции (да, речь шла и идёт о single-threaded варианте) и освобождение его после того как errno скопирована в локальную переменную – это конечно поможет, но только что Вы будете делать с глобальным переменными библиотеки, которые влияют на выполнение последующих вызовов? Будете перед вызовом восстанавливать локальный для потока контекст библиотеки (после захвата спинлока и перед каждым вызовом каждой библиотечной функции, которая не является stateless) и сохранять его каждый раз после окончания вызова (и до освобождения спинлока)?
А что Вы будете делать с той частью контекста, которая Вам не доступна или о котором Вам вообще ничего неизвестно (если Вы, конечно, не являетесь автором библиотеки)? В результате всё и закончится тем самым вырожденным случаем (или его вариацией) - ничего лучше в таких условиях сделать нельзя.
[quote:f28ebcc725]Если не изобретать своей собственной классификации, то в общепринятой есть понятие high thread affinity, т.е. объект/библиотека привязаны к одному потоку и вызов из других потоков не гарантирует правильную работу. Существует масса примеров high thread affinity (STA COM object, окно и т.д.). [/quote:f28ebcc725]
Приходится изобретать, так как устойчивой "общепринятой" не существует. Да и потом, это совсем и не моё изобретение (а жаль ). Что касается thread affinity и всего что с этим связано – это терминология и, соответственно, классификация принятая преимущественно в COM. Посмотрите в гугле – поиск по (“thread affinity”) или (“thread affinity” COM) даёт одни и те же результаты.
[quote:f28ebcc725]Кроме того есть понятие thread unsafe - от пользователя требуется некоторый набор телодвижений чтобы все работало. Требования могут быть разные, от просто блокировки одновременных обращений, до требования использовать конкретный поток для любых обращений. [/quote:f28ebcc725]
Ваше определение thread-unsafe включает high thread affinity ("требования использовать конкретный поток для любых обращений"). Что только ещё один аргумент за то, что такая классификация шире, чем нужно. Слишком много разного между single-threaded и thread-safe вмещается. А тот случай, о котором шла речь как о thread-neutral - просто очень важен практически: Вам гарантируется, что при соблюдении неких несложных правил Вы получите максимально возможный concurrency.
Попробую на примере STL ещё раз пояснить, что попадает в эту категорию: до тех пор пока разные потоки не работают с одними и теми же экземплярами объектов, доступных пользователю, никаких проблем нет. В противном случае пользователь защищает доступные ему им объекты (как созданные им, так и те, которые уже есть в библиотеке, скажем std::cout) сам. О минимально необходимой но достаточной синхронизации доступа к внутренним объектам, недоступных пользователю (и только о них - ни о чём больше) библиотека позаботится сама - это гарантируется. В общем, подход в духе Эйнштейна: "as simple as possible, but not simpler".
[quote:f28ebcc725]Т.е. предположим, что поток A занимается сложной обработкой и вначале захватил mutex, после чего заснул на некоторое время. Тут от пользователя пришел короткий запрос, который требует захвата того же mutex. Т.к. thread B не может захватить этот mutex он засыпает. Имеем два thread-a которые оба спят, пользователь ждет. Через некоторое время просыпается А делает часть работы и опять засыпает. Thread B все равно ждет.[/quote:f28ebcc725]
Wrong. Речь шла не о "засыпать": добровольно отдать CPU отнюдь не то же самое, что "разбуди меня через столько-то миллисекунд". Поэтому в этой ситуации, диспетчер сразу вернёт CPU потоку А - это же ясно из исходного текста: "если все ждут того самого ресурса, то они и не буду претендовать на CPU".
[quote:f28ebcc725]В конечном итоге, вместо того чтобы пользователь получил ответ, что запрошенный ресурс недоступен, он прождет все время, пока обрабатывается сложный запрос.[/quote:f28ebcc725]
Этого как раз и пытаются избегать, бедному пользователю обычно таких страшных вещей не сообщают . Наоборот, TP системы, как правило, сами "разводят" конфликтующие по ресурсам транзакции. Можно, конечно, немедленно (или после конфигурируемого timeout) прекратить транзакцию, которой не повезло нарваться на ожидание, но это имеет обычно смысл только в каких-то специальных случаях.
Что касается вообще техник синхронизации и диспетчеризации в тех же системах обработки транзакций – если Вы хотите больше подробностей или если Вам что-то кажется нелогичным или неправильным – можно, конечно, поговорить подробнее, но это слишком большая тема. Есть масса толковых статей и книг, где это всё можно найти.
Cheers
-
- Уже с Приветом
- Posts: 5552
- Joined: 20 Mar 2001 10:01
- Location: SFBA
-
- Уже с Приветом
- Posts: 991
- Joined: 09 Sep 2001 09:01
- Location: The Earth
Re: Про интервью в Майкрософт... - new branch
[quote:d248472fdb="tengiz"]Начало здесь: http://forum.privet.com/viewtopic.php?t=21442&start=80
Есть масса толковых статей и книг, где это всё можно найти.[/quote:d248472fdb]
Уважаемый Тенгиз, не могли бы Вы порекомендовать толковые статьи и книги на обсуждаемую тему или дать имена авторов / ключевые слова для поиска.
Спасибо
Есть масса толковых статей и книг, где это всё можно найти.[/quote:d248472fdb]
Уважаемый Тенгиз, не могли бы Вы порекомендовать толковые статьи и книги на обсуждаемую тему или дать имена авторов / ключевые слова для поиска.
Спасибо
Best regards,
Michael Popov
Michael Popov
-
- Уже с Приветом
- Posts: 1474
- Joined: 11 Feb 2001 10:01
- Location: Atlanta, GA, USA
-
- Уже с Приветом
- Posts: 4468
- Joined: 21 Sep 2000 09:01
- Location: Sammamish, WA
Re: Про интервью в Майкрософт... - new branch
[quote:4224d380e5="Michael Popov"]...не могли бы Вы порекомендовать толковые статьи и книги на обсуждаемую тему или дать имена авторов / ключевые слова для поиска...[/quote:4224d380e5]
Например вот это:
* Библия - Transaction Processing: Concepts and Techniques by Jim Gray, Andreas Reuter.
* Concurrency Control and Recovery in Database Systems by Philip A. Bernstein and others - эта книга также доступна в электронном виде на странице автора.
Если нужно что-либо попроще, то можно почитать соответствующие главы из Database Management Systems by Raghu Ramakrishnan, Johannes Gehrke.
Ключевые слова: "transaction processing", "concurrency control", "transaction isolation", "locking protocols", "multigranular locking", "multilevel locking", "two phase locking".
Одни из самых известных авторов: уже упоминавшиеся Jim Gray и Phil Bernstein, а также David Lomet, C. Mohan.
Например вот это:
* Библия - Transaction Processing: Concepts and Techniques by Jim Gray, Andreas Reuter.
* Concurrency Control and Recovery in Database Systems by Philip A. Bernstein and others - эта книга также доступна в электронном виде на странице автора.
Если нужно что-либо попроще, то можно почитать соответствующие главы из Database Management Systems by Raghu Ramakrishnan, Johannes Gehrke.
Ключевые слова: "transaction processing", "concurrency control", "transaction isolation", "locking protocols", "multigranular locking", "multilevel locking", "two phase locking".
Одни из самых известных авторов: уже упоминавшиеся Jim Gray и Phil Bernstein, а также David Lomet, C. Mohan.
Cheers
-
- Уже с Приветом
- Posts: 1211
- Joined: 02 Jul 2000 09:01
- Location: SFBA
[quote:c8ca8784e9="tengiz"]... В системах обработки транзакций основанных на блокировках один из способов обеспечения непротиворечивости – это следование протоколу двухфазной блокировки, суть которого грубо в том, что любая транзакция состоит из двух фаз:
фаза 1 - это накопление блокировок: при этом ни одна из захваченных ранее блокировок не отпускается до конца транзакции;
фаза 2 - конец транзакции и высвобождение всех накопленных блокировок.
Что означает, что после захвата ресурса А, при попытке захватить ресурс Б в случае, когда тот уже захвачен другой транзакцией, потоку придётся отдать CPU каким-либо способом - т.е. фигурально выражаясь мы "захватили мьютекс и заснули". Вариант одновременного захвата А и Б не работает в случаях когда транзакция заранее не знает, какие ресурсы по ходу дела могут понадобиться, кроме того, таких ресурсов может быть слишком много, чтобы можно было использовать, скажем, WaitForMultipleObjects.
[/quote:c8ca8784e9]
Тенгиз, если позволите, пару вопросов по поводу способов реализации блокировок:
насколько я понял, в описанном Вами случае подразумевается 1)использование Win32 synchronization objects для захвата ресурсов во время 1-й фазы и 2) захват ресурса производит thread, непостредственно обрабатывающий запрос (поправьте, если это не так). В таком случае, если общее количество ресурсов достаточно велико, не будет ли накладно держать mutex (или другой объект) для каждого ресурса? Как быть в случае, если ресурсы "появляются" в процессе работы, то есть на примере абстрактной СУБД, блокирующей на уровне, например, страницы - как осущесвляется связь между страницей (ресурсом) и соответствующим synchronization object? Похоже, что без многоуровневой блокировки тут ничего не получится...
Вопросы, конечно, дилетанские, общий ответ - надо учить матчасть, но за не имением других...
Буду благодарен, если сочтете возможным ответить.
Упс, сразу не заметил Ваш ответ Михаилу, спасибо за ссылки, буду изучать.
С уважением,
Владимир
фаза 1 - это накопление блокировок: при этом ни одна из захваченных ранее блокировок не отпускается до конца транзакции;
фаза 2 - конец транзакции и высвобождение всех накопленных блокировок.
Что означает, что после захвата ресурса А, при попытке захватить ресурс Б в случае, когда тот уже захвачен другой транзакцией, потоку придётся отдать CPU каким-либо способом - т.е. фигурально выражаясь мы "захватили мьютекс и заснули". Вариант одновременного захвата А и Б не работает в случаях когда транзакция заранее не знает, какие ресурсы по ходу дела могут понадобиться, кроме того, таких ресурсов может быть слишком много, чтобы можно было использовать, скажем, WaitForMultipleObjects.
[/quote:c8ca8784e9]
Тенгиз, если позволите, пару вопросов по поводу способов реализации блокировок:
насколько я понял, в описанном Вами случае подразумевается 1)использование Win32 synchronization objects для захвата ресурсов во время 1-й фазы и 2) захват ресурса производит thread, непостредственно обрабатывающий запрос (поправьте, если это не так). В таком случае, если общее количество ресурсов достаточно велико, не будет ли накладно держать mutex (или другой объект) для каждого ресурса? Как быть в случае, если ресурсы "появляются" в процессе работы, то есть на примере абстрактной СУБД, блокирующей на уровне, например, страницы - как осущесвляется связь между страницей (ресурсом) и соответствующим synchronization object? Похоже, что без многоуровневой блокировки тут ничего не получится...
Вопросы, конечно, дилетанские, общий ответ - надо учить матчасть, но за не имением других...
Буду благодарен, если сочтете возможным ответить.
Упс, сразу не заметил Ваш ответ Михаилу, спасибо за ссылки, буду изучать.
С уважением,
Владимир
-
- Уже с Приветом
- Posts: 991
- Joined: 09 Sep 2001 09:01
- Location: The Earth
По поводу описанной схемы двух фазной блокировки.
Если я правильно понял описанный механизм, то похоже тут возможны два "скверных" сценария:
1) Каждая (или достаточно много) транзакция в начале выполнения пытается залокировать один и тот же ресурс. Результат: полная сериализация.
2) Два типа транзакций A and B. Транзакция типа A локирует ресурс X в начале выполнения и ресурс Y - в конце. Транзакция типа B локирует ресурс Y начале выполнения и ресурс X - в конце. Результат: при равномерном распределении транзакций A and B система будет виснуть на deadlocks.
Оба сценария, разумеется, можно избежать, если транзакции спланированы с учетом особенностей работы механизма блокировки, но в общем случае это не есть хорошо, т.к. особенности сервисного механизма (системы блокировки) накладывают существенные ограничения на прикладной код (business logic).
Если я правильно понял описанный механизм, то похоже тут возможны два "скверных" сценария:
1) Каждая (или достаточно много) транзакция в начале выполнения пытается залокировать один и тот же ресурс. Результат: полная сериализация.
2) Два типа транзакций A and B. Транзакция типа A локирует ресурс X в начале выполнения и ресурс Y - в конце. Транзакция типа B локирует ресурс Y начале выполнения и ресурс X - в конце. Результат: при равномерном распределении транзакций A and B система будет виснуть на deadlocks.
Оба сценария, разумеется, можно избежать, если транзакции спланированы с учетом особенностей работы механизма блокировки, но в общем случае это не есть хорошо, т.к. особенности сервисного механизма (системы блокировки) накладывают существенные ограничения на прикладной код (business logic).
Best regards,
Michael Popov
Michael Popov
-
- Уже с Приветом
- Posts: 4468
- Joined: 21 Sep 2000 09:01
- Location: Sammamish, WA
Big Cheese, что касается всего, что связано непосредственно с Win32 - я упоминал просто для иллюстрации. Вы правы, и реальные системы устроены конечно сложнее и объекты синхронизации, предоставляемые ОС, как правило, не используются напрямую в качестве тех же блокировок, которые, вообще говоря, являются уже довольно высокоуровневыми объектами - их поведение сложнее, чем поведение примитивов синхронизации. Например, на них детектируются deadlock-и, в любой момент можно получить полный список текущих блокировок с их владельцми и очередями ожидания и т.д.
Один из вариант реализации того, что называтеся абстрактный менеджер блокировок – это подсистема, имеющая дело с абстрактными ресурсами, идентифицируемыми, скажем, именами. Его потроха при этом получаются практически независимыми от внутренних механизмов операционной системы. Абстрактный менеджер блокировок ничего не знает и об иерархии ресурсов – для него это просто строки символов. Соблюдение того или иного протокола блокировки - уже забота других частей системы, которые являются клиентами менеджера блокировок.
Скажем, когда транзакции понадобится shared lock слота X, на странице Y, в файле Z, то описываемый вариант менеджер получит запрос на sh блокировку ресурса по имени «X:Y:Z». Если кто-то уже держит блокировку этого ресурса, несовместимую с запрашиваемой, то новый запрос в будет поставлен в очередь ожидания ресурса. И так далее.
Один из вариант реализации того, что называтеся абстрактный менеджер блокировок – это подсистема, имеющая дело с абстрактными ресурсами, идентифицируемыми, скажем, именами. Его потроха при этом получаются практически независимыми от внутренних механизмов операционной системы. Абстрактный менеджер блокировок ничего не знает и об иерархии ресурсов – для него это просто строки символов. Соблюдение того или иного протокола блокировки - уже забота других частей системы, которые являются клиентами менеджера блокировок.
Скажем, когда транзакции понадобится shared lock слота X, на странице Y, в файле Z, то описываемый вариант менеджер получит запрос на sh блокировку ресурса по имени «X:Y:Z». Если кто-то уже держит блокировку этого ресурса, несовместимую с запрашиваемой, то новый запрос в будет поставлен в очередь ожидания ресурса. И так далее.
Cheers
-
- Уже с Приветом
- Posts: 4468
- Joined: 21 Sep 2000 09:01
- Location: Sammamish, WA
Michael Popov, да всё правильно. И то и другое возможно. Так что Ваш вывод абсолютно справедлив - внутренняя механика работы такой системы накладывает ограничения на то, как с ней нужно общаться. Хотя, системы обработки транзакций не являются строго говоря приложениями, а именно системами, которые теперь уже прикладному программисту, как правило, напрямую недоступны: они скрыты ещё одним слоем - процессором запросов. Что, конечно, не мешает нарваться на deadlock, нужно только правильные запросы в правильной последовательности запустить.
Cheers
-
- Уже с Приветом
- Posts: 1211
- Joined: 02 Jul 2000 09:01
- Location: SFBA
-
- Новичок
- Posts: 52
- Joined: 24 Oct 1999 09:01
- Location: Santa Clara, CA
Re: Про интервью в Майкрософт... - new branch
[quote:fd7e289478="tengiz"]
Захват спинлока перед вызовом runtime функции (да, речь шла и идёт о single-threaded варианте) и освобождение его после того как errno скопирована в локальную переменную – это конечно поможет, но только что Вы будете делать с глобальным переменными библиотеки, которые влияют на выполнение последующих вызовов? Будете перед вызовом восстанавливать локальный для потока контекст библиотеки (после захвата спинлока и перед каждым вызовом каждой библиотечной функции, которая не является stateless) и сохранять его каждый раз после окончания вызова (и до освобождения спинлока)?
[/quote:fd7e289478]
Может быть. Все зависит от задачи. Существуют задачи которые проще решать в рамках одного потока и не заботится о синхронизации, а существуют задачи где легче полагаться на операционную систему/внешний планировщик для парралельной обработки. Если восстановление контекста легче чем написание своего собственного планировщика (а это в большинстве случаев именно так) и дает приемлемые результаты, то почему бы не восстанавливать контекст (предполагается что известно, что нужно восстанавливать).
[quote:fd7e289478] А что Вы будете делать с той частью контекста, которая Вам не доступна или о котором Вам вообще ничего неизвестно (если Вы, конечно, не являетесь автором библиотеки)? В результате всё и закончится тем самым вырожденным случаем (или его вариацией) - ничего лучше в таких условиях сделать нельзя.
[/quote:fd7e289478]
Скажем так, для C-runtime и STL это не так. Для очень большого числа библиотек это тоже не так, хотя бы из-за того что они расспространяются с исходными кодами и что и как нужно синхронизировать известно.
[quote:fd7e289478]
Приходится изобретать, так как устойчивой "общепринятой" не существует. Да и потом, это совсем и не моё изобретение (а жаль ). Что касается thread affinity и всего что с этим связано – это терминология и, соответственно, классификация принятая преимущественно в COM. Посмотрите в гугле – поиск по (“thread affinity”) или (“thread affinity” COM) даёт одни и те же результаты.
[/quote:fd7e289478]
Да, вот только при этом Google предупреждает ""COM" is a very common word and was not included in your search".
[quote:fd7e289478]
Ваше определение thread-unsafe включает high thread affinity ("требования использовать конкретный поток для любых обращений"). Что только ещё один аргумент за то, что такая классификация шире, чем нужно. Слишком много разного между single-threaded и thread-safe вмещается. А тот случай, о котором шла речь как о thread-neutral - просто очень важен практически: Вам гарантируется, что при соблюдении неких несложных правил Вы получите максимально возможный concurrency.
[/quote:fd7e289478]
В том то и дело, что не моя. Достаточно в том же Google набрать thread safe и thread neutral. Проблема thread safety слишком распространненая, чтобы не было устоявшихся терминов.
[quote:fd7e289478]
Wrong. Речь шла не о "засыпать": добровольно отдать CPU отнюдь не то же самое, что "разбуди меня через столько-то миллисекунд". Поэтому в этой ситуации, диспетчер сразу вернёт CPU потоку А - это же ясно из исходного текста: "если все ждут того самого ресурса, то они и не буду претендовать на CPU".
[/quote:fd7e289478]
В том то и дело, что не ясно. Я с начала флейма пытаюсь понять, чем системный планировщик не устраивает, и почему STL при соответсвующей синхронизации не работает.
Захват спинлока перед вызовом runtime функции (да, речь шла и идёт о single-threaded варианте) и освобождение его после того как errno скопирована в локальную переменную – это конечно поможет, но только что Вы будете делать с глобальным переменными библиотеки, которые влияют на выполнение последующих вызовов? Будете перед вызовом восстанавливать локальный для потока контекст библиотеки (после захвата спинлока и перед каждым вызовом каждой библиотечной функции, которая не является stateless) и сохранять его каждый раз после окончания вызова (и до освобождения спинлока)?
[/quote:fd7e289478]
Может быть. Все зависит от задачи. Существуют задачи которые проще решать в рамках одного потока и не заботится о синхронизации, а существуют задачи где легче полагаться на операционную систему/внешний планировщик для парралельной обработки. Если восстановление контекста легче чем написание своего собственного планировщика (а это в большинстве случаев именно так) и дает приемлемые результаты, то почему бы не восстанавливать контекст (предполагается что известно, что нужно восстанавливать).
[quote:fd7e289478] А что Вы будете делать с той частью контекста, которая Вам не доступна или о котором Вам вообще ничего неизвестно (если Вы, конечно, не являетесь автором библиотеки)? В результате всё и закончится тем самым вырожденным случаем (или его вариацией) - ничего лучше в таких условиях сделать нельзя.
[/quote:fd7e289478]
Скажем так, для C-runtime и STL это не так. Для очень большого числа библиотек это тоже не так, хотя бы из-за того что они расспространяются с исходными кодами и что и как нужно синхронизировать известно.
[quote:fd7e289478]
Приходится изобретать, так как устойчивой "общепринятой" не существует. Да и потом, это совсем и не моё изобретение (а жаль ). Что касается thread affinity и всего что с этим связано – это терминология и, соответственно, классификация принятая преимущественно в COM. Посмотрите в гугле – поиск по (“thread affinity”) или (“thread affinity” COM) даёт одни и те же результаты.
[/quote:fd7e289478]
Да, вот только при этом Google предупреждает ""COM" is a very common word and was not included in your search".
[quote:fd7e289478]
Ваше определение thread-unsafe включает high thread affinity ("требования использовать конкретный поток для любых обращений"). Что только ещё один аргумент за то, что такая классификация шире, чем нужно. Слишком много разного между single-threaded и thread-safe вмещается. А тот случай, о котором шла речь как о thread-neutral - просто очень важен практически: Вам гарантируется, что при соблюдении неких несложных правил Вы получите максимально возможный concurrency.
[/quote:fd7e289478]
В том то и дело, что не моя. Достаточно в том же Google набрать thread safe и thread neutral. Проблема thread safety слишком распространненая, чтобы не было устоявшихся терминов.
[quote:fd7e289478]
Wrong. Речь шла не о "засыпать": добровольно отдать CPU отнюдь не то же самое, что "разбуди меня через столько-то миллисекунд". Поэтому в этой ситуации, диспетчер сразу вернёт CPU потоку А - это же ясно из исходного текста: "если все ждут того самого ресурса, то они и не буду претендовать на CPU".
[/quote:fd7e289478]
В том то и дело, что не ясно. Я с начала флейма пытаюсь понять, чем системный планировщик не устраивает, и почему STL при соответсвующей синхронизации не работает.
-
- Уже с Приветом
- Posts: 4468
- Joined: 21 Sep 2000 09:01
- Location: Sammamish, WA
Re: Про интервью в Майкрософт... - new branch
Так как со всем остальным более-менее ясно и не очень интересно, то давайте поговорим о:
[quote:839981dcec="__Vlad__"]...Я с начала флейма пытаюсь понять, чем системный планировщик не устраивает, и почему STL при соответсвующей синхронизации не работает.[/quote:839981dcec]
Я надеялся, что это было понятно. Если мои объяснения оказались туманными, то тогда поговорим подробнее.
Есть явление, впервые описанное аж в 1977 году, которое называется “The Convoy Phenomenon”. К сожалению, я не смог найти общедоступный сайт с текстом оригинальной статьи (Mike W. Blasgen, Jim Gray, Michael F. Mitoma, Thomas G. Price: The Convoy Phenomenon. Operating Systems Review 13(2): 20-25(1979)), поэтому ссылку дать не могу. Однако пояснений по этому поводу можно обнаружить массу. Поэтому если будут ещё вопросы – пожалуйста, попробуйте поискать сами.
Суть явления в том, что при наличии high-traffic locks, в системах обработки транзакций такие lock-и нужны, скажем, для buffer manager (database-optimized virtual memory) и log manager (журнал для write ahead logging), вытесняющая многозадачность может привести к тому, что система начинает тратить аномально много времени на переключение контекста. Что приводит к существенному падению производительности и проблемам с масштабируемостью:
High-traffic lock – это объект синхронизации, которые в течение одного кванта много раз (скажем, >100) захватывается на короткое время (пусть это будет < квант/1000). Причём есть много потоков, которые именно так и работают. Так как поток не знает, когда его вытеснят и, кроме того, не имеет возможности сказать системе, чтобы его не вытесняли, вполне может получиться так, что поток, захвативший high-traffic lock, будет вытеснен.
При попытке захватить lock (скажем, он реализован на критической секции со спинлоком) поток, получивший управление, будет помещён в очередь ожидания и система отдаст управление следующему потоку, с которым случится ровно то же самое, пока cpu по циклу не вернётся к потоку, который и захватил нашу критическую секцию. Продолжив выполнение, поток отдаст критическую секцию (что немедленно поместит первый в очереди ожидания поток в очередь готовых к выполнению потоков) и через t < 1/100 кванта попытается опять захватить критическую секцию. Понятно, что у него ничего не выйдет – критическая секция уже захвачена, и поток окажется немедленно вытесненным и помещённым в очереди ожидания.
А дальше уже всё по кругу. Как только поток, который теперь держит критическую секцию, её отдаст (через t < 1/100 кванта), следующий в очереди тут же её захватит, и окажется в очереди готовых к выполнению. Что приведёт к тому, что при очередной попытке захвата (опять же, через t < 1/100 кванта) держателя критической секции вытеснят и поместят в очередь ожидания. И т.д.
В общем, получается, что у нас переключение контекста начинает происходить в >100 раз чаще, чем это обычно бывает. Так как это довольно дорогая операция (по сравнению с захватом той же критической секции), то и получается, что значительные ресурсы системы начинают тратиться на диспетчеризацию.
Один из вариантов решения проблемы – использование non-preemptive scheduling, что гарантирует, что поток, захвативший high-traffic lock не будет вытеснен в самый неподходящий момент. Так как в той же Win32 отсутствует поддержка полноценного non-preemptive scheduling (fibers таковой не являются, хотя бы потому, что для них нет TLS и потому, что для объектов синхронизации это всё равно один и тот же поток).
Именно тут и могут вылезти боком внешние библиотеки, которые могут вызвать неожиданное переключение контекста.
[quote:839981dcec="__Vlad__"]...Я с начала флейма пытаюсь понять, чем системный планировщик не устраивает, и почему STL при соответсвующей синхронизации не работает.[/quote:839981dcec]
Я надеялся, что это было понятно. Если мои объяснения оказались туманными, то тогда поговорим подробнее.
Есть явление, впервые описанное аж в 1977 году, которое называется “The Convoy Phenomenon”. К сожалению, я не смог найти общедоступный сайт с текстом оригинальной статьи (Mike W. Blasgen, Jim Gray, Michael F. Mitoma, Thomas G. Price: The Convoy Phenomenon. Operating Systems Review 13(2): 20-25(1979)), поэтому ссылку дать не могу. Однако пояснений по этому поводу можно обнаружить массу. Поэтому если будут ещё вопросы – пожалуйста, попробуйте поискать сами.
Суть явления в том, что при наличии high-traffic locks, в системах обработки транзакций такие lock-и нужны, скажем, для buffer manager (database-optimized virtual memory) и log manager (журнал для write ahead logging), вытесняющая многозадачность может привести к тому, что система начинает тратить аномально много времени на переключение контекста. Что приводит к существенному падению производительности и проблемам с масштабируемостью:
High-traffic lock – это объект синхронизации, которые в течение одного кванта много раз (скажем, >100) захватывается на короткое время (пусть это будет < квант/1000). Причём есть много потоков, которые именно так и работают. Так как поток не знает, когда его вытеснят и, кроме того, не имеет возможности сказать системе, чтобы его не вытесняли, вполне может получиться так, что поток, захвативший high-traffic lock, будет вытеснен.
При попытке захватить lock (скажем, он реализован на критической секции со спинлоком) поток, получивший управление, будет помещён в очередь ожидания и система отдаст управление следующему потоку, с которым случится ровно то же самое, пока cpu по циклу не вернётся к потоку, который и захватил нашу критическую секцию. Продолжив выполнение, поток отдаст критическую секцию (что немедленно поместит первый в очереди ожидания поток в очередь готовых к выполнению потоков) и через t < 1/100 кванта попытается опять захватить критическую секцию. Понятно, что у него ничего не выйдет – критическая секция уже захвачена, и поток окажется немедленно вытесненным и помещённым в очереди ожидания.
А дальше уже всё по кругу. Как только поток, который теперь держит критическую секцию, её отдаст (через t < 1/100 кванта), следующий в очереди тут же её захватит, и окажется в очереди готовых к выполнению. Что приведёт к тому, что при очередной попытке захвата (опять же, через t < 1/100 кванта) держателя критической секции вытеснят и поместят в очередь ожидания. И т.д.
В общем, получается, что у нас переключение контекста начинает происходить в >100 раз чаще, чем это обычно бывает. Так как это довольно дорогая операция (по сравнению с захватом той же критической секции), то и получается, что значительные ресурсы системы начинают тратиться на диспетчеризацию.
Один из вариантов решения проблемы – использование non-preemptive scheduling, что гарантирует, что поток, захвативший high-traffic lock не будет вытеснен в самый неподходящий момент. Так как в той же Win32 отсутствует поддержка полноценного non-preemptive scheduling (fibers таковой не являются, хотя бы потому, что для них нет TLS и потому, что для объектов синхронизации это всё равно один и тот же поток).
Именно тут и могут вылезти боком внешние библиотеки, которые могут вызвать неожиданное переключение контекста.
Cheers
-
- Новичок
- Posts: 52
- Joined: 24 Oct 1999 09:01
- Location: Santa Clara, CA
[quote:d093d5b277="tengiz"]
Один из вариантов решения проблемы – использование non-preemptive scheduling, что гарантирует, что поток, захвативший high-traffic lock не будет вытеснен в самый неподходящий момент. Так как в той же Win32 отсутствует поддержка полноценного non-preemptive scheduling (fibers таковой не являются, хотя бы потому, что для них нет TLS и потому, что для объектов синхронизации это всё равно один и тот же поток).
[/quote:d093d5b277]
То что в Win32 отсутсвует non-preemptive scheduling я как раз приветствую, а то бы NT приходилось бы перегружать пару раз на дню, как это требовали Windows 3.x при наличии 3-rd party программ . А вот описанную проблему не обязательно решать совсем запрещая системе переключать потоки: достаточно иметь возможность увеличивать и уменьшать приоритеты потока. Если custom scheduling это игра на приоритетах, то тогда я не понимаю каким образом вмешивается STL .
Один из вариантов решения проблемы – использование non-preemptive scheduling, что гарантирует, что поток, захвативший high-traffic lock не будет вытеснен в самый неподходящий момент. Так как в той же Win32 отсутствует поддержка полноценного non-preemptive scheduling (fibers таковой не являются, хотя бы потому, что для них нет TLS и потому, что для объектов синхронизации это всё равно один и тот же поток).
[/quote:d093d5b277]
То что в Win32 отсутсвует non-preemptive scheduling я как раз приветствую, а то бы NT приходилось бы перегружать пару раз на дню, как это требовали Windows 3.x при наличии 3-rd party программ . А вот описанную проблему не обязательно решать совсем запрещая системе переключать потоки: достаточно иметь возможность увеличивать и уменьшать приоритеты потока. Если custom scheduling это игра на приоритетах, то тогда я не понимаю каким образом вмешивается STL .
-
- Уже с Приветом
- Posts: 4468
- Joined: 21 Sep 2000 09:01
- Location: Sammamish, WA
[quote:1a5fc7f76d="__Vlad__"]То что в Win32 отсутсвует non-preemptive scheduling я как раз приветствую, а то бы NT приходилось бы перегружать пару раз на дню, как это требовали Windows 3.x при наличии 3-rd party программ . А вот описанную проблему не обязательно решать совсем запрещая системе переключать потоки: достаточно иметь возможность увеличивать и уменьшать приоритеты потока. Если custom scheduling это игра на приоритетах, то тогда я не понимаю каким образом вмешивается STL .[/quote:1a5fc7f76d]
Наличие non-preemtive scheduling совсем не означает риск получить проблемы, единственное решение которых перезагрузка системы. Что-то типа userland threads в Solaris было бы то, что нужно: non-preemptive друг относительно друга становятся только псевдопотоки, обслуживаемые одним реальным потоком. Т.е. проблема зависания строго локализована в одном потоке одного процесса.
А custom scheduling на приоритетах тоже, строго говоря, нерабочий вариант: NT с его priority boost и попыткой быть слишком добрым к потокам низкого приоритета совсем не гарантирует невытеснение потока высокого приоритета в неподходящий момент- вероятность получить convoy хоть и невысока, но, тем не менее, ненулевая.
Наличие non-preemtive scheduling совсем не означает риск получить проблемы, единственное решение которых перезагрузка системы. Что-то типа userland threads в Solaris было бы то, что нужно: non-preemptive друг относительно друга становятся только псевдопотоки, обслуживаемые одним реальным потоком. Т.е. проблема зависания строго локализована в одном потоке одного процесса.
А custom scheduling на приоритетах тоже, строго говоря, нерабочий вариант: NT с его priority boost и попыткой быть слишком добрым к потокам низкого приоритета совсем не гарантирует невытеснение потока высокого приоритета в неподходящий момент- вероятность получить convoy хоть и невысока, но, тем не менее, ненулевая.
Cheers
-
- Новичок
- Posts: 52
- Joined: 24 Oct 1999 09:01
- Location: Santa Clara, CA
[quote:177cd3ca15="tengiz"]А custom scheduling на приоритетах тоже, строго говоря, нерабочий вариант: NT с его priority boost и попыткой быть слишком добрым к потокам низкого приоритета совсем не гарантирует невытеснение потока высокого приоритета в неподходящий момент- вероятность получить convoy хоть и невысока, но, тем не менее, ненулевая.[/quote:177cd3ca15]
На NT начиная с 4.0 вроде можно запретить dynamic priority boosts, но сам я этого никогда не делал, поэтому настаивать на таком решении не буду.
На NT начиная с 4.0 вроде можно запретить dynamic priority boosts, но сам я этого никогда не делал, поэтому настаивать на таком решении не буду.
-
- Уже с Приветом
- Posts: 3211
- Joined: 20 Mar 2002 10:01
- Location: Chelyabinsk->Rain City,WA->Moscow
Эк вас прорвало то
раз тут собрались такие корифеи программирования у меня к вам вопрос
Как из ASP вызвать COM+ объект. из клиента на С++ или Delphi получается (через TLB). из ASP страницы нет (не доходит даже до создания объекта). IDispatch которым пользуются скриптовые языки должен автоматически маршалиться универсальным маршалером. однако нет
раз тут собрались такие корифеи программирования у меня к вам вопрос
Как из ASP вызвать COM+ объект. из клиента на С++ или Delphi получается (через TLB). из ASP страницы нет (не доходит даже до создания объекта). IDispatch которым пользуются скриптовые языки должен автоматически маршалиться универсальным маршалером. однако нет
-
- Уже с Приветом
- Posts: 1436
- Joined: 27 Apr 2001 09:01
- Location: Moscow
[quote:d1a01971d3]Как из ASP вызвать COM+ объект.[/quote:d1a01971d3]
set obj_com= server.createobject("DLL_Name.Com_Object_Name")
'example
set conn= obj_com.get_any_conn("connection_string")
Только учтите, что асп поддерживает возврат из комов только тип integer и variant Правда можно обойти это, используя тип параметра "byref"
set obj_com= server.createobject("DLL_Name.Com_Object_Name")
'example
set conn= obj_com.get_any_conn("connection_string")
Только учтите, что асп поддерживает возврат из комов только тип integer и variant Правда можно обойти это, используя тип параметра "byref"
-
- Уже с Приветом
- Posts: 3211
- Joined: 20 Mar 2002 10:01
- Location: Chelyabinsk->Rain City,WA->Moscow
[quote:4c113d1d25="Henry"][quote:4c113d1d25]Как из ASP вызвать COM+ объект.[/quote:4c113d1d25]
set obj_com= server.createobject("DLL_Name.Com_Object_Name")
[/quote:4c113d1d25]
спасибо это я чайник. я не про синтаксис спрашивал. надо было Aggregation включить, а то объект не создавался. там заморочка была с aggregation и object pooling - как оказалось одно без другого не работает и наоборот.
[quote:4c113d1d25="Henry"]
Только учтите, что асп поддерживает возврат из комов только тип integer и variant Правда можно обойти это, используя тип параметра "byref"[/quote:4c113d1d25]
мой объект возвращает ADO рекордсет и все работает
(в idl включено import "msado15.dll"" )
set obj_com= server.createobject("DLL_Name.Com_Object_Name")
[/quote:4c113d1d25]
спасибо это я чайник. я не про синтаксис спрашивал. надо было Aggregation включить, а то объект не создавался. там заморочка была с aggregation и object pooling - как оказалось одно без другого не работает и наоборот.
[quote:4c113d1d25="Henry"]
Только учтите, что асп поддерживает возврат из комов только тип integer и variant Правда можно обойти это, используя тип параметра "byref"[/quote:4c113d1d25]
мой объект возвращает ADO рекордсет и все работает
(в idl включено import "msado15.dll"" )
-
- Уже с Приветом
- Posts: 1772
- Joined: 06 Sep 2001 09:01
- Location: Boston, MA -> Charlotte,NC ->Danbury,CT
[quote:ef9bfc3ac5="awaken"][quote:ef9bfc3ac5="Henry"][quote:ef9bfc3ac5]Как из ASP вызвать COM+ объект.[/quote:ef9bfc3ac5]
set obj_com= server.createobject("DLL_Name.Com_Object_Name")
[/quote:ef9bfc3ac5]
спасибо это я чайник. я не про синтаксис спрашивал. надо было Aggregation включить, а то объект не создавался. там заморочка была с aggregation и object pooling - как оказалось одно без другого не работает и наоборот.
[quote:ef9bfc3ac5="Henry"]
Только учтите, что асп поддерживает возврат из комов только тип integer и variant Правда можно обойти это, используя тип параметра "byref"[/quote:ef9bfc3ac5]
мой объект возвращает ADO рекордсет и все работает
(в idl включено import "msado15.dll"" )[/quote:ef9bfc3ac5]
Потому, что в ADO Recordset реализован custom marshalling
set obj_com= server.createobject("DLL_Name.Com_Object_Name")
[/quote:ef9bfc3ac5]
спасибо это я чайник. я не про синтаксис спрашивал. надо было Aggregation включить, а то объект не создавался. там заморочка была с aggregation и object pooling - как оказалось одно без другого не работает и наоборот.
[quote:ef9bfc3ac5="Henry"]
Только учтите, что асп поддерживает возврат из комов только тип integer и variant Правда можно обойти это, используя тип параметра "byref"[/quote:ef9bfc3ac5]
мой объект возвращает ADO рекордсет и все работает
(в idl включено import "msado15.dll"" )[/quote:ef9bfc3ac5]
Потому, что в ADO Recordset реализован custom marshalling
-
- Уже с Приветом
- Posts: 2107
- Joined: 04 Mar 1999 10:01
- Location: Gaithersburg, MD
Re: Про интервью в Майкрософт... - new branch
[quote:fc3827f2e1="tengiz"]
Один из вариантов решения проблемы – использование non-preemptive scheduling, что гарантирует, что поток, захвативший high-traffic lock не будет вытеснен в самый неподходящий момент. Так как в той же Win32 отсутствует поддержка полноценного non-preemptive scheduling (fibers таковой не являются, хотя бы потому, что для них нет TLS и потому, что для объектов синхронизации это всё равно один и тот же поток).
[/quote:fc3827f2e1]А почему нельзя просто повысить приоритет потока сразу после захвата high-traffic lock?
Один из вариантов решения проблемы – использование non-preemptive scheduling, что гарантирует, что поток, захвативший high-traffic lock не будет вытеснен в самый неподходящий момент. Так как в той же Win32 отсутствует поддержка полноценного non-preemptive scheduling (fibers таковой не являются, хотя бы потому, что для них нет TLS и потому, что для объектов синхронизации это всё равно один и тот же поток).
[/quote:fc3827f2e1]А почему нельзя просто повысить приоритет потока сразу после захвата high-traffic lock?
-
- Уже с Приветом
- Posts: 4468
- Joined: 21 Sep 2000 09:01
- Location: Sammamish, WA
Re: Про интервью в Майкрософт... - new branch
[quote:bfc92cb9fe="Victor"][quote:bfc92cb9fe="tengiz"]
Один из вариантов решения проблемы – использование non-preemptive scheduling, что гарантирует, что поток, захвативший high-traffic lock не будет вытеснен в самый неподходящий момент. Так как в той же Win32 отсутствует поддержка полноценного non-preemptive scheduling (fibers таковой не являются, хотя бы потому, что для них нет TLS и потому, что для объектов синхронизации это всё равно один и тот же поток).
[/quote:bfc92cb9fe]А почему нельзя просто повысить приоритет потока сразу после захвата high-traffic lock?[/quote:bfc92cb9fe]
Можно, но, во-первых, нет гарантии, что поток не будет вытеснен после захвата lock и перед повышением приоритета. Во-вторых даже высокий приоритет (в динамическом, а не real-time диапазоне - но работа в real-time диапазоне - это совсем отдельная песня) не гарантирует невытеснения, если есть хотя бы один готовый к выполнению поток любого приоритета. Мы уже это обсуждали чуть выше.
Один из вариантов решения проблемы – использование non-preemptive scheduling, что гарантирует, что поток, захвативший high-traffic lock не будет вытеснен в самый неподходящий момент. Так как в той же Win32 отсутствует поддержка полноценного non-preemptive scheduling (fibers таковой не являются, хотя бы потому, что для них нет TLS и потому, что для объектов синхронизации это всё равно один и тот же поток).
[/quote:bfc92cb9fe]А почему нельзя просто повысить приоритет потока сразу после захвата high-traffic lock?[/quote:bfc92cb9fe]
Можно, но, во-первых, нет гарантии, что поток не будет вытеснен после захвата lock и перед повышением приоритета. Во-вторых даже высокий приоритет (в динамическом, а не real-time диапазоне - но работа в real-time диапазоне - это совсем отдельная песня) не гарантирует невытеснения, если есть хотя бы один готовый к выполнению поток любого приоритета. Мы уже это обсуждали чуть выше.
Cheers