Не может спровоцировать инверсию приоритетов в C ++ - PullRequest
3 голосов
/ 20 марта 2012

Я пытаюсь вызвать Priority Inversion на маленькой C ++ программе для демонстрационных целей, но не могу: поток с низким приоритетом, который содержит мьютекс , не являетсявыгружается и продолжает работать в критической секции.Вот что я делаю:

// let's declare a global mutex
pthread_mutex_t my_mutex;
  ...

int main(int argc, char **argv) {
  ...
  pthread_t normal_thread;
  pthread_t prio_thread;

  pthread_mutexattr_t attr;
  pthread_mutexattr_init (&attr);
  pthread_mutexattr_setprotocol (&attr, PTHREAD_PRIO_NONE);  // ! None !
  pthread_mutex_init(&my_mutex, &attr);

  // create first normal thread (L):
  pthread_create(&normal_thread, NULL, the_locking_start_routine, NULL);

  // just to help the normal thread enter in the critical section
  sleep(2);

  // now will launch:
  // * (M) several CPU intensive SCHED_FIFO threads with priority < 99
  // * (H) one SCHED_FIFO thread that will try to lock the mutex, with priority < 99

  // build Real Time attributes for the Real Time threads:
  pthread_attr_t my_rt_att;
  pthread_attr_init(&my_rt_att);

  // it was missing in the original post and it was also wrong:
  // even setting the SchedPolicy you have to set "InheritSched"
  pthread_attr_setinheritsched(&my_rt_att, PTHREAD_EXPLICIT_SCHED)

  pthread_attr_setschedpolicy(&my_rt_att, SCHED_FIFO);
  struct sched_param params;

  params.sched_priority = 1;
  pthread_attr_setschedparam(&my_rt_att, &params);

  pthread_create(&prio_thread, &my_rt_att, the_CPU_intensive_start_routine, NULL) 

  params.sched_priority = 99;
  pthread_attr_setschedparam(&my_rt_att, &params);

  // create one RealTime thread like this:
  pthread_create(&prio_thread, &my_rt_att, the_locking_start_routine, NULL)  //coma was missing

  ...
}

void *the_locking_start_routine(void *arg) {
  ...
  pthread_mutex_lock(&my_mutex);
  // This thread is on the critical section
  // ... (skipped)
  pthread_mutex_unlock(&my_mutex);
  ...
}

... Но это не работает, у меня не может быть желаемой приоритетной инверсии.

Вот что происходит:

Как я понимаю, с таким планировщиком, как Linux CFS, поток не в реальном времени (SCHED_OTHER) не будет работать, пока не будет потока в реальном времени (SCHED_FIFO или SCHED_RR) в состоянии выполнения.Но я добился того, чтобы эти потоки работали одновременно:

  • (L) Один поток не в реальном времени (SCHED_OTHER) блокирует мьютекс и потребляет процессор
  • (M) нескольких потоков реального времени (SCHED_FIFO, & priority> 0) Процессор интенсивно и не ожидает блокировки мьютекса
  • (H) Один поток реального времени (SCHED_FIFO, & наивысший приоритет) ожидает блокировки

Работает больше потоков, интенсивно использующих процессор (M) в реальном времени, чем количество процессоров в моей системе ... но поток не в реальном времени, удерживающий (L) блокировку, все еще потребляет процессор и завершает свою работу и освобождает мьютекс до того, какПотоки "M" завершают загрузку процессора.

Почему поток с низким приоритетом не прерывается, приложение блокируется, и я не могу получить инверсию приоритета?

Я использую g ++ 4.5.2 на Ubuntu Desktop 11.04 с ядром 2.6.38-13.

Ответы [ 3 ]

5 голосов
/ 20 марта 2012

Re: Я пытаюсь спровоцировать Priority Inversion на небольшую программу C ++ для демонстрационных целей, но не могу: поток с низким приоритетом, который содержит мьютекс, не выгружается и продолжает работать ...

То, что является началом сценария инверсии приоритета. Поток с низким приоритетом получает эксклюзивный ресурс (например, мьютекс), в котором потоки с высоким приоритетом затем блокируются.

Чтобы правильно отобразить последствия инверсии приоритетов, вам потребуется, например, три потока: поток с низким (L), средним (M) и высоким (H) приоритетом.

L блокирует мьютекс, за который борется H. Так что L работает, H нет. Это уже плохо: важный поток H ждет, пока менее важный поток L что-то сделает.

Теперь M становится работоспособным и требует больших вычислительных ресурсов. М не заботится о мьютексе; он не связан с H или L. Но M имеет более высокий приоритет, чем L, и выбивает L из процессора.

Так что теперь M продолжает выполняться, не давая L работать. Это препятствует тому, чтобы L достиг строки кода, где это освобождает мьютекс, и это препятствует тому, чтобы H получил мьютекс.

Таким образом, выполняется поток со средним приоритетом M вместо потока с самым высоким приоритетом H.

Блокируя L, M также может блокировать H: инверсия.

Посмотрим, сможете ли вы его так закодировать.

3 голосов
/ 20 марта 2012
  1. Запускаете ли вы программу от имени пользователя root?

  2. Каковы ваши значения этих параметров sysctl?Вот мой из коробки с Ubuntu.По умолчанию в режиме реального времени дается только 0,95 секунды из 1-секундного среза:

    kernel.sched_rt_period_us = 1000000
    kernel.sched_rt_runtime_us = 950000
    

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

См .: http://www.kernel.org/doc/Documentation/scheduler/sched-rt-group.txt

Если вы установите sched_rt_runtime_us в -1, вы отключите этопредохранительный механизм.

1 голос
/ 20 марта 2012

Большинство современных планировщиков имеют средства защиты от взаимоблокировок, которые изменяют приоритет на интервал времени или два, чтобы предотвратить инверсию приоритетов, приводящую к взаимоблокировкам, когда они обнаружены или сочтены целесообразными. Будь Linux с любым планировщиком, который вы используете с ним, я не знаю точно. Однако имейте это в виду, если вы этого еще не сделали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...