Я новичок в Linux и Linux темы. Я потратил некоторое время на поиск в Google, чтобы понять разницу между всеми функциями, доступными для синхронизации потоков. У меня все еще есть вопросы.
Я обнаружил все эти различные типы синхронизации, каждая из которых имеет ряд функций для блокировки, разблокировки, тестирования блокировки и т. Д.
- gcc атомарные операции
- futexes
- мьютексы
- 1012 * Взаимные блокировки *
- seqlocks
- rculocks
- условия
- семафоров
Мое нынешнее (но, вероятно, ошибочное) понимание таково:
Семафоры имеют широкий процесс, включают файловую систему (я полагаю, что это практически так) и, вероятно, являются самыми медленными.
Futexes может быть базовым механизмом блокировки, используемым мьютексами, спин-блокировками, seqlocks и rculocks. Futexes может быть быстрее, чем механизмы блокировки на их основе.
Спинлоки не блокируют и, таким образом, избегают скачков контекста. Однако они избегают переключения контекста за счет использования всех циклов ЦП до снятия блокировки (вращения). Их следует использовать только в многопроцессорных системах по понятным причинам. Никогда не спи в спинлок.
Блокировка seq просто сообщает вам, когда вы закончили работу, если писатель изменил данные, на которых была основана работа. Вы должны вернуться и повторить работу в этом случае.
Атомарные операции являются самым быстрым синхронизирующим вызовом и, вероятно, используются во всех вышеупомянутых механизмах блокировки. Вы не хотите использовать атомарные операции над всеми полями в ваших общих данных. Вы хотите использовать блокировку (mutex, futex, spin, seq, rcu) или одну атомарную операцию над флагом блокировки при доступе к нескольким полям данных.
Мои вопросы звучат так:
Прав ли я до сих пор со своими предположениями?
Кто-нибудь знает стоимость цикла процессора различных опций? Я добавляю параллелизм к приложению, чтобы мы могли лучше реагировать на настенное время за счет запуска меньшего количества экземпляров приложения на ящик. Представления - самое большое внимание. Я не хочу использовать процессор с переключением контекста, вращением или множеством дополнительных циклов процессора для чтения и записи общей памяти. Я абсолютно обеспокоен количеством циклов процессора.
Какие (если таковые имеются) блокировки предотвращают прерывание потока планировщиком или прерыванием ... или я просто идиот, и все механизмы синхронизации делают это. Какие виды прерывания предотвращены? Могу ли я заблокировать все потоки или потоки только на процессоре блокирующего потока? Этот вопрос связан с моим страхом прерывания потока, удерживающего блокировку для очень часто используемой функции. Я ожидаю, что планировщик может запланировать любое количество других работников, которые, вероятно, столкнутся с этой функцией и затем заблокируют, потому что она была заблокирована. Большая часть переключения контекста будет потрачена впустую, пока поток с блокировкой не будет перенесен и завершен. Я могу переписать эту функцию, чтобы минимизировать время блокировки, но все же она так часто называется, что я хотел бы использовать блокировку, которая предотвращает прерывание ... на всех процессорах.
Я пишу код пользователя ... поэтому я получаю программные прерывания, а не аппаратные ... верно? Я должен держаться подальше от любых функций (блокировки spin / seq), в которых есть слово "irq".
Какие блокировки предназначены для написания кода ядра или драйвера, а какие предназначены для пользовательского режима?
Кто-нибудь думает, что использование атомарной операции для перемещения нескольких потоков по связанному списку - чокнутый? Я думаю атомарно изменить указатель текущего элемента на следующий элемент в списке. Если попытка сработает, то поток может безопасно использовать данные, на которые указывал текущий элемент, прежде чем он был перемещен. Другие темы теперь будут перемещаться по списку.
futexes? Есть ли основания использовать их вместо мьютексов?
Есть ли лучший способ, чем использовать условие для сна потока, когда нет работы?
При использовании атомарных операций gcc, в частности test_and_set, могу ли я повысить производительность, выполнив сначала неатомарный тест, а затем используя test_and_set для подтверждения? Я знаю, что это будет конкретный случай, так что вот случай. Существует большая коллекция рабочих предметов, скажем, тысячи. Каждый рабочий элемент имеет флаг, который инициализируется равным 0. Когда поток имеет эксклюзивный доступ к рабочему элементу, этот флаг будет равен одному. Там будет много рабочих потоков. Каждый раз, когда поток ищет работу, он не может атомарно проверить на 1. Если они читают 1, мы точно знаем, что работа недоступна. Если они читают ноль, им нужно выполнить атомарный test_and_set для подтверждения. Так что, если атомарный test_and_set равен 500 циклам процессора, потому что он отключает конвейерную обработку, заставляет процессоры обмениваться данными и кэши L2 сбрасываются / заполняются .... и простой тест - 1 цикл .... тогда, пока у меня было лучшее соотношение от 500 до 1, когда дело дошло до того, что мы наткнулись на уже выполненные рабочие задания ... это будет победа.
Я надеюсь использовать мьютексы или спин-блокировки, чтобы спарлиново защитить разделы кода, которые я хочу, чтобы только один поток в СИСТЕМЕ (не только ЦП) имел доступ одновременно. Я надеюсь экономно использовать gcc atomic ops для выбора работы и минимизации использования мьютексов и спин-блокировок. Например: флаг в рабочем элементе может быть проверен, чтобы увидеть, работал ли поток с ним (0 = нет, 1 = да или в процессе). Простой test_and_set сообщает потоку, работает ли он или должен двигаться дальше. Я надеюсь использовать условия для пробуждения потоков, когда есть работа.
Спасибо!