Linux pthread互斥体和内核调度器
与我的一位朋友一起,我们对如何在用户空间级别(在pthread库中)处理同步存在分歧 a。我认为在pthread_mutex_锁定期间,线程会主动等待。这意味着linux调度程序启动此线程,让它执行其代码,该代码应如下所示:Linux pthread互斥体和内核调度器,linux,pthreads,mutex,scheduling,Linux,Pthreads,Mutex,Scheduling,与我的一位朋友一起,我们对如何在用户空间级别(在pthread库中)处理同步存在分歧 a。我认为在pthread_mutex_锁定期间,线程会主动等待。这意味着linux调度程序启动此线程,让它执行其代码,该代码应如下所示: while (mutex_resource->locked); 然后,安排另一个线程,这可能会释放locked字段等。 因此,这意味着调度程序在切换到下一个线程之前等待线程完成其调度时间,而不管线程正在做什么 b。我的朋友认为等待线程不知怎么地告诉内核“嘿,我睡着了
while (mutex_resource->locked);
然后,安排另一个线程,这可能会释放locked
字段等。
因此,这意味着调度程序在切换到下一个线程之前等待线程完成其调度时间,而不管线程正在做什么
b。我的朋友认为等待线程不知怎么地告诉内核“嘿,我睡着了,根本不要等我”。
在这种情况下,内核将立即调度下一个线程,而不必等待当前线程完成其调度时间,因为它知道该线程正在休眠
从我在pthread代码中看到的情况来看,似乎存在处理锁的循环。但也许我错过了什么
在嵌入式系统中,防止内核等待是有意义的。所以他可能是对的(但我希望他不是:D)
谢谢 使用gdb对此测试程序进行一些调试:
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER;
void* thr_func(void *arg)
{
pthread_mutex_lock(&x);
}
int main(int argc, char **argv)
{
pthread_t thr;
pthread_mutex_lock(&x);
pthread_create(&thr, NULL, thr_func, NULL);
pthread_join(thr,NULL);
return 0;
}
#包括
#包括
#包括
#包括
pthread\u mutex\u t x=pthread\u mutex\u初始值设定项;
void*thr_func(void*arg)
{
pthread_mutex_lock(&x);
}
int main(int argc,字符**argv)
{
pthread_t thr;
pthread_mutex_lock(&x);
pthread_create(&thr,NULL,thr_func,NULL);
pthread_join(thr,NULL);
返回0;
}
显示在互斥锁上调用pthread\u mutex\u lock
会导致调用系统调用futex
,并将op
参数设置为futex\u WAIT
()
这是FUTEX_WAIT的描述:
FUTEX_,等等
此操作以原子方式验证futex地址
uaddr仍然包含val值,并且睡觉等待FUTEX_唤醒
这是futex的地址。如果超时参数为
非空,其内容描述等待的最大持续时间,
否则是无限的。参数uaddr2和val3是
忽略
因此,从这个描述中,我可以说,如果一个互斥锁被锁定,那么一个线程将休眠,而不是主动等待。它将一直休眠,直到调用了op等于futex_WAKE
的futex
a。我认为在pthread\u mutex\u lock
期间,线程会主动等待
是的,glibc的NPTLpthread\u mutex\u lock
具有活动等待(旋转),
但是旋转只用于非常短的时间,并且只用于某些类型的互斥体。在这个数量之后,pthread\u mutex\u lock
将通过使用WAIT参数调用linux进入睡眠状态
只有类型为PTHREAD\u MUTEX\u ADAPTIVE\u NP的互斥体才会旋转,默认值为PTHREAD\u MUTEX\u TIMED\u NP
(正常互斥体),不旋转。)
如果要执行无限旋转(活动等待),请将函数与pthread\u spinlock\u t
-类型锁定一起使用
我将考虑你的问题,就像你使用的是<代码> pthRead SpulyLoop< <代码>:
然后,调度另一个线程,这可能会释放锁定的字段等。因此,这意味着调度程序在切换到下一个线程之前会等待线程完成调度时间,而不管线程在做什么 是的,如果存在对CPU内核的争用,则具有活动旋转的线程可能会阻止其他线程执行,即使另一个线程将解锁线程所需的互斥锁(spinlock) 但是,如果没有争用(没有线程超额订阅),并且线程被安排在不同的内核上(通过巧合,或者通过使用sched_setaffinity
或手动设置cpu亲和力),旋转将使您能够更快地进行,然后使用基于操作系统的futex
b。我的朋友认为等待线程不知怎么地告诉内核“嘿,我睡着了,根本不要等我”。在这种情况下,内核将立即调度下一个线程,而无需等待当前线程完成
是的,他是对的
futex
是一种现代的方式,表示操作系统中的线程正在等待内存中的某个值(用于打开一些互斥体
);在当前的实现中,futex
也使我们的线程处于休眠状态。如果内核知道何时唤醒这个线程,就不需要唤醒它来进行旋转。它怎么知道?锁所有者在执行pthread\u mutex\u unlock
时,将检查是否有其他线程在该互斥锁上睡眠。如果有,锁所有者将使用futex\u WAKE
调用futex
,告诉操作系统唤醒一些线程,在这个互斥锁上注册为睡眠线程
如果线程在操作系统中注册为服务员,则无需旋转。嗯,我可能错了,但我没有相同的理解:在这个FUTEX地址上等待FUTEX_唤醒。如果函数正在休眠(而不是线程),这是一个活动等待,对吗?
futex
syscall有参数“lock变量的地址”和“lock变量的预期值”。该地址用于将同一互斥体上的futex调用者链接在一起,而不是链接等待不同互斥体的线程。Sleeper将向OS显示它正在等待的地址,unlock时的lock owner(OS,为lock owner工作)将使用相同的(物理)地址查找等待此互斥锁的任何线程,并在需要新的lock值时唤醒其中一个Waiter。休眠/取消休眠的内核端机制是什么?@BeeOnRope,Unix中有许多睡眠机制,如select/poll和向unsleep发送信号(以及各种API)。对于linux中的线程,有(线程是进程,管理器“线程”使用SIGUSR1/2来唤醒)、建议的NGPT,现在有了真正的1:1线程和futex(,;内核2.6.*,2.6.40+,…)。查看pdf的第8页。