3

出于演示目的,我试图在一个小型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) 线程锁定互斥体并消耗 CPU
  • (M) 几个实时线程 (SCHED_FIFO , & priority > 0) CPU 密集型和非等待锁定互斥锁
  • (H) 一个等待锁的实时线程(SCHED_FIFO 和最高优先级)

运行的实时 CPU 密集型线程 (M) 比我系统的 CPU 数量多……但持有锁的非实时线程 (L) 仍在消耗 CPU 并完成它的工作并在“M”个线程完成消耗 CPU。

为什么低优先级线程没有被抢占,应用程序死锁,我无法获得优先级反转?

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

4

3 回答 3

5

回复:出于演示目的,我试图在一个小型 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:反转。

看看你能不能把它完全像这样编码。

于 2012-03-20T00:20:44.673 回答
3
  1. 您是否以 root 身份运行该程序?

  2. 这些 sysctl 参数的值是多少?这是我的一个 Ubuntu 盒子。默认设置是在 1 秒切片中仅提供 0.95 秒的实时时间:

    kernel.sched_rt_period_us = 1000000
    kernel.sched_rt_runtime_us = 950000
    

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

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

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

于 2012-03-20T16:04:53.307 回答
1

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

于 2012-03-20T15:19:53.443 回答