Re[5]: внутренняя реализация std::mutex?
От: Videoman Россия https://hts.tv/
Дата: 17.05.18 19:02
Оценка:
Здравствуйте, andrey.desman, Вы писали:

AD>Нет, конечно, не утверждал, но учитывая вышенаписанное, ты скорее сам исходники смотрел не шибко внимательно.


Да, просмотрел. В случае если, таки, необходимо засыпать, используется WaitForSingleObjectEx и поток уходит в ядро. Вся остальная реализация в user-mode. Т.е. все достаточно не плохо под Винду . Некоторые другие вещи в CRT меня ужасали, бывало.
Re[7]: внутренняя реализация std::mutex?
От: barney  
Дата: 17.05.18 19:11
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, AlexGin, Вы писали:


AG>>while(lck.test_and_set(std::memory_order_acquire)) [b]// здесь, возможно, придется подождать!


O>Спинлок в такой имплементации — это вообще, как по мне, плохая идея.


Вот, я тоже об этом подумал. Т.к если есть сначала дешевый test в цикле, то шину и кеш не грузим,
а затем по факту освообждения переходим к шагу два с попыткой атомарно захватить. Если не успели — возвращаемся на дешевый цикл чтения.

O>Во-первых, постоянно теребить глобальную переменную с xchg/cmpxchg и блокировкой шины — не есть гуд

O>(bus traffic и все такое). Как минимум, тут надо применять стратегию не "test and set", а
O>"test test and set" + какую-то разгрузку в виде yield/pause/Sleep/etc.

А такое можно реализовать легковесно в user mode не отдавая контекст ядру/планировщику?

O>Во-вторых, на однопроцессорной машине крутиться в спин-цикле бессмысленно, так как лок никто в

O>это время не освободит.

O>Ну и в-третьих, если между захватом и освобождением лока поток будет вытеснен, получится

O>очень некрасивая ситуация по отношению к другим потокам, которые ждут его освобождения.
O>Особенно если лок не гарантирует порядок захвата. Так легко и систему завесить, особенно если
O>такой спинлок применять где-нибудь в критических местах — драйверы, всякие системные
O>обработчики и т.д. Встречал на практике.

Любопытный вопрос. А какие практики используются вместо этого в ядре?
Re[6]: внутренняя реализация std::mutex?
От: Videoman Россия https://hts.tv/
Дата: 17.05.18 19:17
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Хорошо, — вот допустим, что у меня такой вариант "ожидания":

AG>
AG>#include <atomic>
 
AG>class SpinLock
AG>{
AG>public:
AG>    void lock()
AG>    {
AG>        while(lck.test_and_set(std::memory_order_acquire)) // здесь, возможно, придется подождать!
AG>        {}
AG>    }
 
AG>    void unlock()
AG>    {
AG>        lck.clear(std::memory_order_release);
AG>    }
 
AG>private:
AG>    std::atomic_flag lck = ATOMIC_FLAG_INIT;
AG>};
AG>

AG>Взято отсюда:
AG>http://anki3d.org/spinlock

AG>Теперь предположим, что в результате некоторой ситуации все ядра моего CPU ждут на while в методе lock.

AG>Да, случай практически не вероятный, но всё-таки — полностью НЕ исключаемый.
AG>Загрузка всех секций CPU будет под 100% (здесь я даже не спрашиваю насчет полезноти/бесполезности данной вычислительной работы).
AG>Спрошу только одно — сможет ли пользователь хоть как-то взаимодействовать с ОС? Хоть бы для того, чтобы снять эту зависшую задачу?

Ну а зачем так делать? Вот вам принципы из практики на счет производительности, чтобы с многопоточностью все было ок:
1. Как не странно. не разделяйте данные. Если можно, всегда делайте локальные копии данных для каждого потока.
2. Старайтесь все данные через блокировки передавать пакетировано и как можно быстрее. В идеале, все должно сводится к обмену указателей на массив объектов.
3. Spin-Lock дает выигрыш только если количество итераций достаточно мало. В противном случае выгоднее уйти в ядро и не тратить циклы CPU.
Re[8]: внутренняя реализация std::mutex?
От: okman Беларусь https://searchinform.ru/
Дата: 17.05.18 19:21
Оценка:
Здравствуйте, barney, Вы писали:

B>А такое можно реализовать легковесно в user mode не отдавая контекст ядру/планировщику?


Наверное, ничего лучше инструкции pause пока не придумали.

B>Любопытный вопрос. А какие практики используются вместо этого в ядре?


Конкретно ядро Windows перед захватом спинлока задирает IRQL до DISPATCH_LEVEL, это предотвращает вытеснение
потока планировщиком (хотя это не исключает, например, приход прерывания, в результате чего код все равно
будет временно вытеснен). Ну и вместо обычных спинлоков рекомендуется применять спинлоки с очередями на
стеке (in-stack queued spinlock) — там каждый поток вместо глобальной переменной теребит переменную у
себя в стеке, ну и гарантируется порядок захвата спинлока потоками (т.е. убирается проблема "starvation").

Про linux не в курсе, я его видел только "на картинках"

В режиме пользователя запретить вытеснение потока нельзя. Думаю, в режиме пользователя по этой
причине никаких спинлоков быть не должно.
Отредактировано 17.05.2018 19:22 okman . Предыдущая версия .
Re[7]: внутренняя реализация std::mutex?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 17.05.18 20:32
Оценка:
Здравствуйте, AlexGin, Вы писали:

N>>Уточните, под какой ОС такое происходит.

AG>Последний раз видел такую ситуацию — примерно пять лет назад под Windows XP.

Хммм...

N>>Честно, у меня как-то не наблюдалось. Но у меня уже лет 20 что сервера, что десктопы/лаптопы почти сплошь Linux и FreeBSD.


AG>А разве в мире Linux что-то принцыпиально иначе? Разве не будет такой же ситуации?

AG>Если на каждом из ядер крутится свой поток, и не даёт возможности "вклиниться" диспетчеру потоков, то там должно быть аналогично.

С чего это вдруг "должно" быть?
Регулярно приходят таймерные прерывания (или при NOHZ режиме их можно заказывать на конкретные моменты).
Диспетчер отслеживает потребление процессора нитями и делает, чтобы каждая нить из желающих получала долю процессора, максимально близко пропорциональную некоторому числу, зависящему от приоритета.
Кроме этого, есть система временного буста диспетчерского приоритета для нитей, которые до того находились в спячке достаточное время — это помогает типовым интерактивным задачам, которые реагируют на события от пользователя и спят в остальное время; это делается на каком-то варианте token bucket.
Если нить сама не отдаёт процессор, то её по таймерному прерыванию или даже по любому сисколлу могут вытеснить принудительно. Диспетчер всегда имеет право вклиниться и переключить активную нить на любом ядре, кроме сверхкоротких периодов пребывания в kernel land между точками выхода в user land, ожиданий или явных yield'ов.
И мне просто дико слышать, что где-то иначе, тем более что "должно" быть иначе — это ж какой, извините, каменный век в алгоритмах?

(Нет, конечно, не всё так однозначно, я сама дочь офицера есть realtime priority и ещё хитрые фишки того же плана — но вряд ли какой безумец сделает на них thread pool. И, наоборот, есть шейперы, которые позволяют урезать права)

AG>Предположим, что у нас обычный офисный комп с Win10/Win7.

AG>У меня есть приложение, которое (выполняя определенную работу) — дико тормозит все мои пользовательские действия.
AG>Что я могу сделать, как пользователь? Что могу сделать, если приложение сторонее и я НЕ имею его исходных кодов?

Вот был бы Linux — я бы сказал, как сделать, чтобы это приложение не брало более, например, 40% CPU, если есть другие желающие — конкретно, через cgroup/cpu.shares. А с Windows... боюсь, что тут ровно как в знаменитом лозунге про спасение утопающих...
The God is real, unless declared integer.
Re[6]: внутренняя реализация std::mutex?
От: Vain Россия google.ru
Дата: 17.05.18 23:30
Оценка:
Здравствуйте, reversecode, Вы писали:

R>коллективный разум это когда решается какая то проблема доселе не известная или не имеющая решения

R>а как устроены ОС описано в гугле на каждом шагу, плюс куча книг и исходников
R>это называется по другому, — научите меня бесплатно
А сам то ты здесь наверно ошиваешься не для того чтобы учить/учиться, а флеймить ради?
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
Re[7]: внутренняя реализация std::mutex?
От: AlexGin Беларусь  
Дата: 18.05.18 09:02
Оценка:
Здравствуйте, okman, Вы писали:

O>Спинлок в такой имплементации — это вообще, как по мне, плохая идея.


Если этим спинлоком защищать только условные Get/Set для некоторого (общего для потоков) значения, то идея вроде как хорошая.
Но, конечно же, при использовании его есть риск завесить приложение, если вынесли в него некие сложные действия.

O>Во-первых, постоянно теребить глобальную переменную с xchg/cmpxchg и блокировкой шины — не есть гуд

O>(bus traffic и все такое). Как минимум, тут надо применять стратегию не "test and set", а
O>"test test and set" + какую-то разгрузку в виде yield/pause/Sleep/etc.
+100500
Вот именно о разгрузке в виде ::Sleep — я и сообщал здесь выше!
В виде Sleep или WaitingFor... ввести ожидание, чтобы передать управление диспетчеру потоков.

O>Во-вторых, на однопроцессорной машине крутиться в спин-цикле бессмысленно, так как лок никто в

O>это время не освободит.

Да, однопроцессорных сейчас уже давно нет, но когда-то (лет 15 назад) как-то же работала многопоточка?

O>Ну и в-третьих, если между захватом и освобождением лока поток будет вытеснен, получится

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

Вероятность того, что поток будет вытеснен, если внутри этого лока — только один вызов гетера/сетера — фактически нулевая.

O>Особенно если лок не гарантирует порядок захвата. Так легко и систему завесить, особенно если

O>такой спинлок применять где-нибудь в критических местах — драйверы, всякие системные
O>обработчики и т.д. Встречал на практике.
+100500
Да, если внутрь этого лока вносить что-то длинное, то такое бывает. Я когда-то также сталкивался с этим.
Но здесь — вся ответственность на разработчике
Каких-либо механизмов, способных разрулить проблему IMHO не существует.
Кроме, разве что сделать ожидание в локе — с прокачкой сообщений ОС, и с вызовом Sleep...
Отредактировано 18.05.2018 9:33 AlexGin . Предыдущая версия . Еще …
Отредактировано 18.05.2018 9:08 AlexGin . Предыдущая версия .
Re[7]: внутренняя реализация std::mutex?
От: AlexGin Беларусь  
Дата: 18.05.18 09:22
Оценка:
Здравствуйте, Videoman, Вы писали:

AG>>Теперь предположим, что в результате некоторой ситуации все ядра моего CPU ждут на while в методе lock.

AG>>Да, случай практически не вероятный, но всё-таки — полностью НЕ исключаемый.
AG>>Загрузка всех секций CPU будет под 100% (здесь я даже не спрашиваю насчет полезноти/бесполезности данной вычислительной работы).
AG>>Спрошу только одно — сможет ли пользователь хоть как-то взаимодействовать с ОС? Хоть бы для того, чтобы снять эту зависшую задачу?

V>Ну а зачем так делать? Вот вам принципы из практики на счет производительности, чтобы с многопоточностью все было ок:

V>1. Как не странно. не разделяйте данные. Если можно, всегда делайте локальные копии данных для каждого потока.

Есть немалая вероятность, что когда-либо эти данные окажутся рассинхронизированы (будут иметь различные значения, вместо одного).

V>2. Старайтесь все данные через блокировки передавать пакетировано и как можно быстрее. В идеале, все должно сводится к обмену указателей на массив объектов.

+100500
Это бесспорно так.

V>3. Spin-Lock дает выигрыш только если количество итераций достаточно мало. В противном случае выгоднее уйти в ядро и не тратить циклы CPU.

+100500
Здесь также согласен.
Re[6]: внутренняя реализация std::mutex?
От: AlexGin Беларусь  
Дата: 18.05.18 09:40
Оценка:
Здравствуйте, lpd, Вы писали:

lpd>Здравствуйте, AlexGin, Вы писали:


AG>Да, но есть риск получить систему полностью загруженной, когда она перестанет отзываться на действия пользователя.

AG>Вполне возможно, что в цикле рабочего потока ::Sleep(100) — не вызовет катастрофических задержек.
AG>Однако, вызвав диспетчер потоков позволит пользователю как-то общаться с машиной, когда запущена твоя вычислительная задача.
AG>В противном случае — компьютер становиться страшно тормознутым и практически не управляемым

lpd>Лучше уменьшить приоритет вычислительной задаче через системный менеджер процессов, например, или из кода.


Так получится, что уменьшение приоритета даст примерно тот же эффект (если не хуже),
в плане снижения производительности, что тот же самый ::Sleep
Re: внутренняя реализация std::mutex?
От: barney  
Дата: 18.05.18 14:59
Оценка:
Нашел любопытный разбор легковесных мьютексов под win32

http://preshing.com/20120226/roll-your-own-lightweight-mutex/
Re[8]: внутренняя реализация std::mutex?
От: okman Беларусь https://searchinform.ru/
Дата: 18.05.18 15:07
Оценка:
Здравствуйте, AlexGin, Вы писали:

AG>Вероятность того, что поток будет вытеснен, если внутри этого лока — только один вызов гетера/сетера — фактически нулевая.


Смысл в том, что она все равно не нулевая.
У нас в софте были такие зависания, оказалось там была схожая реализация лока с циклом на CMPXCHG.
Код под локом — всего несколько процессорных инструкций, но все равно иногда случалось, что
он вытеснялся и система висла (потому что за лок конкурировали другие важные потоки системы).
Когда переделали на стандартные виндовые spinlock/pushlock — все заработало.

AG>Каких-либо механизмов, способных разрулить проблему IMHO не существует.

AG>Кроме, разве что сделать ожидание в локе — с прокачкой сообщений ОС, и с вызовом Sleep...

Ну в ядре, как я уже писал, можно на время запретить переключение контекстов, ядерные
спинлоки так и работают (повышая IRQL до соответствующего уровня, где шедулер не работает).
Re[2]: внутренняя реализация std::mutex?
От: okman Беларусь https://searchinform.ru/
Дата: 18.05.18 16:09
Оценка: 3 (1)
Здравствуйте, barney, Вы писали:

B>Нашел любопытный разбор легковесных мьютексов под win32


B>http://preshing.com/20120226/roll-your-own-lightweight-mutex/


На Windows Vista и выше есть вот это:

Slim Reader/Writer (SRW) Locks
https://msdn.microsoft.com/en-us/library/windows/desktop/aa904937(v=vs.85).aspx

Это легковесный аналог mutex/крит.секции, но поддерживающий семантику 'читатели-писатель'.
Re[2]: внутренняя реализация std::mutex?
От: Videoman Россия https://hts.tv/
Дата: 19.05.18 09:00
Оценка:
Здравствуйте, barney, Вы писали:

B>Нашел любопытный разбор легковесных мьютексов под win32


А что в нем легковесного? В случае неудачи сразу же блокировать конкурента. Обыкновенная критическая секция намного эффективнее будет.
Re[3]: внутренняя реализация std::mutex?
От: AlexGin Беларусь  
Дата: 19.05.18 10:23
Оценка:
Здравствуйте, okman, Вы писали:

O>На Windows Vista и выше есть вот это:


O>Slim Reader/Writer (SRW) Locks

O>https://msdn.microsoft.com/en-us/library/windows/desktop/aa904937(v=vs.85).aspx

O>Это легковесный аналог mutex/крит.секции, но поддерживающий семантику 'читатели-писатель'.


Интересная штуковина!
Вот нагуглил примерчик по применению:
https://www.codeproject.com/Articles/32685/Testing-reader-writer-locks
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.