Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.223.196.171] |
|
Страницы: (16) « Первая ... 3 4 [5] 6 7 ... 15 16 все ( Перейти к последнему сообщению ) |
Сообщ.
#61
,
|
|
|
Убрал template c GetSharedPtrLock(). Теперь они все будут лочиться одним счётчиком. Плохо конечно, но не смертельно. Понять, это ли было причиной ошибки на сервере я не смог, но в случае с потоками лучше перебдеть
Добавлено Цитата Flex Ferrum @ Даже если ты делаешь синхронизацию на спинлоках - это все равно лочка, и алгоритм с такой синхронизацией lock-free назвать уже нельзя А разве не именно такие алгоритмы называются lock-free? Которые блокируют ресурс не усыпляя потока? |
Сообщ.
#62
,
|
|
|
Цитата Олег М @ А разве не именно такие алгоритмы называются lock-free? Которые блокируют ресурс не усыпляя потока? Если я всё правильно понимаю, то нет: Цитата Для алгоритмов без блокировок гарантируется системный прогресс по крайней мере одного потока. Например, поток, выполняющий операцию «сравнение с обменом» в цикле, теоретически может выполняться бесконечно, но каждая его итерация означает, что какой-то другой поток совершил прогресс, то есть система в целом совершает прогресс. Добавлено В вики на этот счёт всё хорошо расписано. |
Сообщ.
#63
,
|
|
|
Цитата Flex Ferrum @ Если я всё правильно понимаю, то нет: Цитата Судя по цитате, понимаешь неправильно. Но не буду тут спорить, я в этом не большой специалист. Моё понимание таково - усыплять поток, потом будить - это дорого. Для многопроцессорных систем дешевле, чтоб этот поток покрутился в цикле, пока другой поток, который как правило крутится на другом другом процессоре, освободит ресурс. Единственная проблема там - в атомик-блокировках, о которых я знаю совсем мало, но говорят, что они тоже нифига не бесплатные. |
Сообщ.
#64
,
|
|
|
Цитата Олег М @ Моё понимание таково - усыплять поток, потом будить - это дорого. Для многопроцессорных систем дешевле, чтоб этот поток покрутился в цикле, пока другой поток, который как правило крутится на другом другом процессоре, освободит ресурс. Нет. Самый дорогой ресурс - процессорное время. Если потоку не нужно работать, пусть остановится. |
Сообщ.
#65
,
|
|
|
Цитата ЫукпШ @ Нет. Самый дорогой ресурс - процессорное время. Если потоку не нужно работать, пусть остановится. Тут я не соглашусь. Остановка-запуск потока далеко не бесплатные операции и их тоже выполняет тот же самый процессор. |
Сообщ.
#66
,
|
|
|
Цитата Олег М @ Цитата Flex Ferrum @ Если я всё правильно понимаю, то нет: Цитата Судя по цитате, понимаешь неправильно. Но не буду тут спорить, я в этом не большой специалист. Моё понимание таково - усыплять поток, потом будить - это дорого. Для многопроцессорных систем дешевле, чтоб этот поток покрутился в цикле, пока другой поток, который как правило крутится на другом другом процессоре, освободит ресурс. Единственная проблема там - в атомик-блокировках, о которых я знаю совсем мало, но говорят, что они тоже нифига не бесплатные. Весьма ошибочное суждение. Потоков в системе обычно на порядки больше, чем голов у процессора. Поэтому система шедулрует на одном процессоре/голове несколько десятков, если не сотен, потоков. И если какой-то из потоков начнёт крутить пустой цикл - он впустую сжигает ватты и мешает работать другим. Кстати, именно этим плохи спинлоки, особенно самопальные. Дорого контекстами щелкать - прыгать от одного потока к другому и обратно (т. н. "дребезг") - вот это да, действительно дорого. Поток должен стараться с максимальной пользой утилизировать свои кванты. Этим и хороши lock-free алгоритмы (при грамотно использовании) - на критических путях нету взаимных блокировок и простоев. Но и они не панацея. |
Сообщ.
#67
,
|
|
|
А чем самопальные спинлоки отличаются о не-самопальных.
Добавлено Цитата Flex Ferrum @ Дорого контекстами щелкать - прыгать от одного потока к другому и обратно (т. н. "дребезг") - вот это да, действительно дорого. Поток должен стараться с максимальной пользой утилизировать свои кранты. Этим и хороши lock-free алгоритмы (при грамотно использовании) - на критических путях нету взаимных блокировок и простоев. Но и они не панацея. Что-то ни слова не понял. Что значит "щёлкать контекстами" - усыплять один поток и пробуждать другой, разве мьютексы так и не делают? Что значит нету взаимных блокировок - куда ж они тогда деваются? |
Сообщ.
#68
,
|
|
|
Цитата Олег М @ А чем самопальные спинлоки отличаются о не-самопальных. Тем, что могут не учитывать особенности работы системы, быть написанными топорно. Системные примитив синхронизацию обычно оптимизированы под "короткие" блокировки и не проваливаются лишний раз в ядро. |
Сообщ.
#69
,
|
|
|
Цитата Flex Ferrum @ Тем, что могут не учитывать особенности работы системы, быть написанными топорно. А как цикл с compare_exchange может не учитывать особенности работы системы? Или учитывать? |
Сообщ.
#70
,
|
|
|
Цитата Flex Ferrum @ 1. У меня там, в Release, вроде префиксный декремент, return --m_cnt == 0; И он проверяется на ноль. В AddRef проверка на ноль нужна, чтобы не захватывать удаляемый элемент. Это я к тому, что и в AddRef можно так же делать. К слову, все так и делают. В смысле, ты имеешь ввиду, почему я не делаю AddRef () {return ++m_cnt != 1;}? Потому что так нельзя. Если счётчик равен нулю, то его нельзя увеличивать, иначе когда несколько потоков будут одновременно вызывать AddRef(), только одному вернётся false, остальным - true и указатель на объект который был удалён. |
Сообщ.
#71
,
|
|
|
Итак - зачем мне это нужно?
1. Тренировка мозгов. Когда работаешь с потоками ошибку сделать легко, но найти её можно только путём пристального разглядывания и анализа исходного кода. Для этого нужно всегда быть в форме и помнить о нюансах и правилах. Lock-free алгоритмы - хорошая тренировка. Добавлено 2. Повторное использования кода. Когда тебе постоянно приходится блокировать экземпляр какого-то класса, придумывать названия для мьютексов, следить, чтобы они блокировались-разблокировались вовремя и тд и тп, поневоле задумаешься - а не сделать ли этот класс потоко-безопасным? Потратить один раз время и забыть об этих проблемах. C классами типа контейнеров, строк и т.д. это делать тяжеловато, да и особо не нужно - они блокируются относительно редко и по-разному. Но указатели - другое дело, они простые, и они используются часто. Добавлено 3. Минимизация времени блокировки. Не думаю (вернее, не знаю как), что можно заблокировать shared_ptr на меньшее время, причём независимо от других указателей. Например есть большое количество объектов, которые создаются/удаляются в одних потоках, обрабатываются в других. Для решения этой задачи я пользуюсь следующим методом: - В обработчике хранится список list<weak_ptr> и мьютекс - Когда мне надо что-то с ним сделать, я блокирую этот мьютекс, переношу список в локальную переменную при помощи move-конструктора, разблокирую - Пробегаюсь по локальному списку, если weak_ptr::lock возвращает null, удаляю из локального списка, иначе вызываю какую-нибудь функцию - Снова блокирую список, делаю list::splice, т.е. возвращаю не удалённые объекты обратно Все операции копеечные и никаких дедлоков |
Сообщ.
#72
,
|
|
|
смотрел смотрел твой код.. сложно не разобраться добавь комментов плз
|
Сообщ.
#73
,
|
|
|
Цитата Олег М @ 3. Минимизация времени блокировки. Критическая секция - вероятно, самый быстрый вариант. --- Тренировка - это отлично. А результат достигнут ? |
Сообщ.
#74
,
|
|
|
Цитата ЫукпШ @ Критическая секция - вероятно, самый быстрый вариант. --- Тренировка - это отлично. А результат достигнут ? Тут спорный вариант, но примерно такой же, но, в любом случае занимает больше памяти. Результат чего? Код вроде работает, пока. Завтра вечером можно будет сказать более определённо. В выходные коннекто мало. Добавлено Цитата Cfon @ смотрел смотрел твой код.. сложно не разобраться добавь комментов плз С этим сложнее, никогда не умел писать комментарии. Лучше спроси, что непонятно – я отвечу. |
Сообщ.
#75
,
|
|
|
Цитата Олег М @ Результат чего? Код вроде работает, пока. Завтра вечером можно будет сказать более определённо. Вот посмотри тут. Ты пишешь: void lock() noexcept { ++m_cnt; } Будет ли этот инкремент - потокобезопасным ? Чисто случайно, я посмотрел ассемблерный текст одного из скомпилированных модулей. И вот что получилось - вот оно: //.. ++Count; //.. стало: ; 191 : ++Count; 0003e a1 00 00 00 00 mov eax, DWORD PTR ?Count@@3HA ; Count 00043 40 inc eax 00044 a3 00 00 00 00 mov DWORD PTR ?Count@@3HA, eax ; Count Никакой потокобезопасностью даже не пахнет. 3 машинные команды, передача управления другому потоку может произойти между ними. Хотя казалось что будет что-то вроде (но увы..): inc DWORD PTR Count |