Программирование ядра - мьютексы - PullRequest
0 голосов
/ 27 сентября 2018

Поэтому я пытаюсь использовать mutex_init(), mutex_lock(), mutex_unlock() для синхронизации потоков.

В настоящее время я пытаюсь планировать потоки в режиме циклического перебора (но более 1 потока можетзапускаться одновременно), и я устанавливаю текущее состояние потока на TASK_INTERRUPTIBLE, после чего просыпается другой поток, чей PID у меня есть в списке.

Мне нужно перебрать этот список для своей логики.

Насколько я понимаю, мне нужно заблокировать этот список при доступе к его элементам, иначе другой поток может пропустить новую запись, пока яВношу изменения в нее.Кроме того, поскольку один мьютекс заблокировал ресурс, никакой другой мьютекс не сможет разблокировать его, пока оригинальный мьютекс не освободит его.

Но я все еще не уверен, правильно ли я его блокирую.(Я снимаю блокировку перед вызовом schedule() и снова блокирую после этого)

Я объявляю мьютекс локально в потоке и блокирую список.После того, как мой текущий поток блокирует

mutex_lock(&lock); 

, и я перебираю список, пока не найду что-то (или не завершу, если ничего не найду), затем разблокирует.

mutex_unlock(&lock);

IПредположим, блокировка, пока я повторяю, является законнойХотя я никогда не видел примеров этого.

Кроме того, нормально ли, что процесс имеет состояние (TASK_UNINTERRUPTIBLE), пока он удерживает блокировку мьютекса?

EDIT: Я добавляю еще немного информации, основываясь на ответе ниже.

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

Я пытаюсь сохранить планирование между потоками, которые имеют определенный идентификатор.Например, если есть 4 темы.2 в наборе «A» и 2 в наборе «B».Я разрешаю запускать только 1 поток в каждом наборе.Но я переключаюсь между потоками в данном наборе.Тем не менее, поток в наборе 'A' не должен переключаться на какой-либо поток в наборе 'B'

(я знаю, что планировщик ядра не будет идеальным, так что приблизительное переключение подойдет).

Мое обоснование для TASK_STATE:

1) Работает начальный созданный поток.

2) Если работает другой поток в том же наборе (и этот не выполнялся в течение заданного времени).Установите для другого потока значение TASK_INTERRUPTIPLE при вызове schedule(); Примечание: В каждом наборе может быть более 2 потоков, но давайте сделаем все просто, рассматривая пока только 2.

3) Если это выполнено в течение достаточного времени, поставьте эту задачуна TASK_INTERRUPTIPLE, установите другую задачу в том же наборе на TASK_RUNNING, при этом вызывая schedule();

Вся эта логика происходит, когда я обращаюсь к определенным структурам данных, которые заблокированы (теперь) Globalмьютекс.Я разблокирую мьютекс как раз перед тем, как позвонить schedule(), и сразу после этого снова блокирую.После того, как моя логическая часть закончена, я полностью разблокирую мьютекс.

Что-то принципиально не так с подходом?

1 Ответ

0 голосов
/ 28 сентября 2018

Насколько я понимаю, мне нужно заблокировать этот список при доступе к его элементам

Да, это правда.Но если вы используете мьютекс, вам будет очень грустно, потому что вызов lock / unlock - это вызов планировщика.Следовательно, вызов его из планировщика должен привести к тупику.Что вам нужно сделать, зависит от того, является ли ваш процессор многоядерным или (мифическим) одноядерным.(Это виртуальная система?) На одноядерном процессоре вы можете отключить прерывания.На многоядерном процессоре отключение прерываний недостаточно (оно отключает прерывания только для этого одного ядра, и другое ядро ​​все еще может прерываться).Самое простое, что можно сделать на многоядерном компьютере, - это использовать спин-блокировку.В отличие от мьютекса, оба эти механизма блокировки могут быть разблокированы из разных потоков.

Я установил текущее состояние потока в TASK_INTERRUPTIBLE

Является ли потокснял процессор?Если это так, он не работает, поэтому я подозреваю, что TASK_INTERRUPTIBLE - неправильное состояние.Было бы полезно, если бы вы могли перечислить возможные состояния для меня или описать, что это состояние должно указывать.Потому что для меня "TASK_INTERRUPTIBLE" звучит как запущенная задача.

Я объявляю мьютекс локально в потоке и блокирую список

Локальные мьютексы - красный флаг!Блокируемый ресурс должен быть защищен мьютексом с той же областью действия.Если список является глобальным, он должен иметь глобальный мьютекс для его защиты.Потоки, которые хотят использовать список, должны сначала получить его мьютекс.Конечно, как я уже говорил, вы, вероятно, захотите использовать другой тип блокировки для защиты списка готовых к запуску процессов.

Я предполагаю, что блокировка во время итерации допустима

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

Кроме того, это нормально для процесса, чтобы иметьсостояние TASK_UNINTERRUPTIBLE пока он удерживает блокировку мьютекса?

Нет, пока он удерживает блокировку, если процесс в данный момент выполняется на процессоре.Мьютекс доступен для пользовательского кода.Если удержание мьютекса сделает процесс бесперебойным, это будет означать, что процесс может захватить систему, просто заблокировав мьютекс и никогда не освободив его.Теперь вы обнаружите, что функции lock и unlock должны быть бесперебойными на одноядерном процессоре.Однако не имеет смысла устанавливать состояние для процесса, потому что на самом деле планировщик не должен прерываться.

...