无法在C ++中激发优先级倒置

时间:2012-03-19 22:46:45

标签: c++ pthreads real-time mutex thread-priority

我试图在一个小的 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这样的scheduller,非实时线程(SCHED_OTHER)将无法运行,直到没有任何实时线程(SCHED_FIFO或SCHED_RR)处于运行状态。但我已经实现了同时运行的这些线程:

  • (L)一个非实时(SCHED_OTHER)线程锁定互斥锁和 消耗CPU
  • (M)几个实时线程(SCHED_FIFO,&amp; priority&gt; 0)CPU 密集且无需等待锁定互斥锁
  • (H)等待一个实时线程(SCHED_FIFO,&amp;最高优先级) 锁定

运行的实时CPU密集型线程(M)比系统的CPU数量多......但非实时线程持有(L)锁仍然消耗CPU并完成它的工作并释放在“M”线程完成消耗CPU之前的互斥锁。

为什么低优先级线程不被抢占,应用程序死锁,我无法获得优先级倒置?

我在内核2.6.38-13的Ubuntu Desktop 11.04上使用g ++ 4.5.2。

3 个答案:

答案 0 :(得分:5)

Re:我试图在一个小的C ++程序上激发优先级倒置以进行演示,但我不能:持有互斥锁的低优先级线程没有被抢占并继续运行......

是优先级反转方案的开始。低优先级线程获取高优先级线程然后阻塞的独占资源(例如互斥锁)。

要正确显示优先级倒置的后果,您需要三个线程:低(L),中(M)和高(H)优先级线程。

L锁定互斥锁,H争辩。所以L在运行,H不是。这已经很糟糕了:重要的线程H正在等待不太重要的线程L做某事。

现在M变得可运行并且是计算密集型的。 M不关心互斥体;它与H或L无关。但是M的优先级高于L,并将L从CPU中拉出来。

所以现在M继续执行,阻止L运行。这可以防止L到达释放互斥锁的代码行,从而阻止H获取互斥锁。

因此,正在运行中优先级线程M而不是最高优先级线程H.

通过阻止L,M也可以阻止H:反转。

看看你是否可以像这样编码。

答案 1 :(得分:3)

  1. 您是否以root身份运行该程序?

  2. 您对这些sysctl参数的值是什么?这是我的Ubuntu盒子。默认设置是在1秒切片中仅实时0.95秒:

    kernel.sched_rt_period_us = 1000000
    kernel.sched_rt_runtime_us = 950000
    

    这可以防止实时域占用所有CPU。如果您想要实时,则必须禁用这些参数。

  3. 请参阅:http://www.kernel.org/doc/Documentation/scheduler/sched-rt-group.txt

    如果将sched_rt_runtime_us设置为-1,则禁用此安全机制。

答案 2 :(得分:1)

大多数现代调度程序都具有防死锁保护措施,可以更改一两个时间片的优先级,以防止在检测到或认为合适时导致死锁的优先级倒置。无论linux是否与您使用的调度程序一起使用,我都不确定。但是,如果你还没有,请注意这一点。