【问题标题】:std::promise::set_value on FIFO thread pinned to a core doesn't wake std::future固定到核心的 FIFO 线程上的 std::promise::set_value 不会唤醒 std::future
【发布时间】:2012-06-26 23:52:02
【问题描述】:

我正在尝试创建一个具有确定性实时响应的系统。

我创建了多个cpusets,将所有非关键任务和未固定的内核线程移动到一组,然后将我的每个实时线程固定到自己的 cpuset,每个 cpuset 都包含一个 cpu。

$ non-critical tasks and unpinned kernel threads
cset proc --move --fromset=root --toset=system
cset proc --kthread --fromset=root --toset=system

$ realtime threads
cset proc --move --toset=shield/RealtimeTest1/thread1 --pid=17651
cset proc --move --toset=shield/RealtimeTest1/thread2 --pid=17654

我的情况是这样的:

  • 线程1:SCHED_OTHER,固定到set1,等待std::future<void>
  • 线程 2:SCHED_FIFO,固定到 set2,调用 std::promise<void>::set_value()

线程 1 永远阻塞。 但是,如果我将线程 2 更改为 SCHED_OTHER,线程 1 可以继续。

我已运行strace -f 以获得更多见解;似乎线程 1 正在等待 futex(我假设是 std::future 的内部),但从未被唤醒。

我完全受阻 - 有没有办法让线程自己连接到核心并将其调度程序设置为 FIFO ,然后使用 std::promise 唤醒另一个等待它完成的线程所以- 所谓的实时设置?

thread1创建thread2的代码如下:

// Thread1:
std::promise<void> p;
std::future <void> f = p.get_future();

_thread = std::move(std::thread(std::bind(&Dispatcher::Run, this, std::ref(p))));

LOG_INFO << "waiting for thread2 to start" << std::endl;

if (f.valid())
    f.wait();

thread2的Run函数如下:

// Thread2:
LOG_INFO << "started: threadId=" << Thread::GetId() << std::endl;

Realtime::Service* rs = Service::Registry::Lookup<Realtime::Service>();
if (rs)
    rs->ConfigureThread(this->Name()); // this does the pinning and FIFO etc

LOG_INFO << "thread2 has started" << std::endl;
p.set_value(); // indicate fact that the thread has started

strace 输出如下:

  • 线程 1 是 [pid 17651]
  • 线程 2 是 [pid 17654]

为了简洁起见,我删除了一些输出。

//////// Thread 1 creates thread 2 and waits on a future ////////

[pid 17654] gettid()                    = 17654
[pid 17651] write(2, "09:29:52 INFO waiting for thread"..., 4309:29:52 INFO waiting for thread2 to start
 <unfinished ...>
[pid 17654] gettid( <unfinished ...>
[pid 17651] <... write resumed> )       = 43
[pid 17654] <... gettid resumed> )      = 17654
[pid 17651] futex(0xd52294, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
[pid 17654] gettid()                    = 17654
[pid 17654] write(2, "09:29:52 INFO thread2 started: t"..., 6109:29:52 INFO thread2  started: threadId=17654
) = 61

//////// <snip> thread2 performs pinning, FIFO, etc </snip> ////////

[pid 17654] write(2, "09:29:52 INFO thread2 has starte"..., 3409:29:52 INFO thread2 has started
) = 34
[pid 17654] futex(0xd52294, FUTEX_CMP_REQUEUE_PRIVATE, 1, 2147483647, 0xd52268, 2) = 1
[pid 17651] <... futex resumed> )       = 0
[pid 17654] futex(0xd522c4, FUTEX_WAKE_PRIVATE, 2147483647 <unfinished ...>
[pid 17651] futex(0xd52268, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 17654] <... futex resumed> )       = 0
[pid 17651] <... futex resumed> )       = 0

//////// blocks here forever ////////

您可以看到 pid 17651 (thread1) 报告 futex resumed,但它是否可能在错误的 cpu 上运行并被阻塞在以 FIFO 运行的 thread2 后面?

更新:这似乎是线程的问题没有在它们被固定到的 CPU 上运行

top -p 17649 -Hf,j 调出last used cpu 表明线程 1 确实在线程 2 的 cpu 上运行

top - 10:00:59 up 18:17,  3 users,  load average: 7.16, 7.61, 4.18
Tasks:   3 total,   2 running,   1 sleeping,   0 stopped,   0 zombie
Cpu(s):  7.1%us,  0.1%sy,  0.0%ni, 89.5%id,  0.0%wa,  0.0%hi,  3.3%si,  0.0%st
Mem:   8180892k total,   722800k used,  7458092k free,    43364k buffers
Swap:  8393952k total,        0k used,  8393952k free,   193324k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  P COMMAND                                                                                                                                                                                             
17654 root      -2   0 54080  35m 7064 R  100  0.4   5:00.77 3 RealtimeTest                                                                                                                                                                                         
17649 root      20   0 54080  35m 7064 S    0  0.4   0:00.05 2 RealtimeTest                                                                                                                                                                                         
17651 root      20   0 54080  35m 7064 R    0  0.4   0:00.00 3 RealtimeTest    

但是,如果我查看 cpuset 文件系统,我可以看到我的任务应该固定在我请求的 CPU 上:

/cpusets/shield/RealtimeTest1 $ for i in `find -name tasks`; do echo $i; cat $i; echo "------------"; done

./thread1/tasks
17651 
------------
./main/tasks
17649 
------------
./thread2/tasks
17654
------------

显示cpuset配置:

$ cset set --list -r
cset: 
         Name       CPUs-X    MEMs-X Tasks Subs Path
 ------------ ---------- - ------- - ----- ---- ----------
         root       0-23 y     0-1 y   279    2 /
       system 0,2,4,6,8,10 n       0 n   202    0 /system
       shield 1,3,5,7,9,11 n       1 n     0    2 /shield
RealtimeTest1    1,3,5,7 n       1 n     0    4 /shield/RealtimeTest1
      thread1          3 n       1 n     1    0 /shield/RealtimeTest1/thread1
      thread2          5 n       1 n     1    0 /shield/RealtimeTest1/thread2
         main          1 n       1 n     1    0 /shield/RealtimeTest1/main

据此,我会说 thread2 应该在 cpu 5 上,但 top 说它在 cpu 3 上运行。

有趣的是,sched_getaffinity 报告了 cpuset 的作用——线程 1 在 cpu 3 上,线程 2 在 cpu 5 上。

但是,查看/proc/17649/task 以找到last_cpu,它的每个任务都运行在:

/proc/17649/task $  for i in `ls -1`; do cat $i/stat | awk '{print $1 " is on " $(NF - 5)}'; done
17649 is on 2
17651 is on 3
17654 is on 3

sched_getaffinity 报告的是一回事,但现实是另一回事

有趣的是,main 线程 [pid 17649] 应该在 cpu 1 上(根据 cset 输出),但实际上它在 cpu 2 上运行(在另一个套接字上)

所以我会说cpuset 不起作用?

我的机器配置是:

$ cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 1
$ uname -a
Linux foobar 2.6.32.12-0.7-default #1 SMP 2010-05-20 11:14:20 +0200 x86_64 x86_64 x86_64 GNU/Linux

【问题讨论】:

  • 我不会投票偏离主题,但我真的不确定这是要问这样一个具体问题的地方,因为它处理内核配置而不是用户代码。也许试试SuperUser.SE
  • @ildjarn - 谢谢 - 我会这样做的
  • 我在serverfault上提出了一个问题:serverfault.com/questions/402575/…
  • 这里的代码在很多方面与另一个问题上发布的代码相似:stackoverflow.com/questions/10843304/… 这个问题是由另一个问题“回答”,还是这个问题是关于同一个问题的不同问题/类似的代码?
  • @MichaelBurr - 我认为你可能是对的,很可能是 - 我会在承诺上使用 std::move 并让你知道结果

标签: c++ linux c++11 real-time scheduler


【解决方案1】:

我在 SLES 11 / SP 2 盒子上重新运行了测试,并且固定工作正常。

因此,我将把它标记为答案,即:这是与 SP 1

相关的问题

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-19
    • 1970-01-01
    • 2022-01-15
    • 2014-11-10
    • 1970-01-01
    • 2019-12-04
    相关资源
    最近更新 更多