Linux pthread互斥和内核调度程序

时间:2014-05-28 10:09:36

标签: linux pthreads mutex scheduling

对于我的一位朋友,我们不同意如何在用户空间级别(在pthread库中)处理同步。

一个。我认为在pthread_mutex_lock期间,线程会主动等待。这意味着linux调度程序升级了这个线程,让它执行他的代码,它应该是:

while (mutex_resource->locked);

然后,计划另一个可能释放locked字段等的线程。 所以这意味着调度程序在切换到下一个之前等待线程完成其调度时间,无论线程在做什么。

湾我的朋友认为等待的线程以某种方式告诉内核"嘿,我睡着了,根本不等我...#34;。 在这种情况下,内核会立即调度下一个线程,而不必等待当前线程完成其调度时间,意识到此线程正在休眠。

从我在pthread的代码中看到的,似乎有循环处理锁。但也许我错过了一些东西。

在嵌入式系统中,防止内核等待是有意义的。所以他可能是对的(但我希望他没有:D)。

谢谢!

2 个答案:

答案 0 :(得分:3)

  

一个。我认为在pthread_mutex_lock期间,线程会主动等待。

是的,glibc的NPTL pthread_mutex_lock有活跃的等待(旋转), 但纺纱仅在非常短的时间内使用,仅适用于某些类型的互斥体。在此金额之后,pthread_mutex_lock将通过使用WAIT参数调用linux syscall futex来进入休眠状态。

只有类型为PTHREAD_MUTEX_ADAPTIVE_NP的互斥锁才会旋转,默认值为PTHREAD_MUTEX_TIMED_NP(正常互斥锁)而不会旋转。 Check MAX_ADAPTIVE_COUNT in __pthread_mutex_lock sources)。

如果你想进行无限旋转(主动等待),请使用pthread_spin_lock函数和pthread_spinlock_t - 类型锁。

我会将您的其余问题视为您使用pthread_spin_lock

  

然后,调度另一个可能释放锁定字段的线程,等等。这意味着调度程序在切换到下一个线程之前等待线程完成其调度时间,无论线程在做什么。

是的,如果存在CPU内核争用,那么具有活动旋转的线程可能阻止其他线程执行,即使另一个线程是解锁线程所需的互斥锁(自旋锁)的线程。

但是如果没有争用(没有线程超额订阅),并且线程被安排在不同的核心上(巧合,或通过手动设置与sched_setaffinitypthread_setaffinity_np的cpu亲和力),旋转将启用你可以更快地进行,然后使用基于操作系统的futex。

  

湾我的朋友认为等待的线程以某种方式告诉内核"嘿,我睡着了,根本不等我...#34;。在这种情况下,内核会立即安排下一个线程,而不必等待当前线程完成...

是的,他是对的。

futex是说OS的一种现代方式,这个线程在内存中等待一些值(用于打开一些mutex);并且在当前实现中futex也使我们的线程进入睡眠状态。如果内核知道何时唤醒此线程,则不需要将其唤醒以进行旋转。怎么知道?锁定所有者在执行pthread_mutex_unlock时会检查是否有其他线程在这个互斥锁上休眠。如果有,锁定所有者将使用futex调用FUTEX_WAKE,告诉操作系统唤醒某些线程,在此互斥锁上注册为睡眠者。

如果线程在OS中将自己注册为服务员,则无需旋转。

答案 1 :(得分:2)

对于此测试程序,使用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_mutex_lock会导致系统调用futex并将op参数设置为FUTEX_WAIThttp://man7.org/linux/man-pages/man2/futex.2.html

这是FUTEX_WAIT:

的描述
  

FUTEX_WAIT

     

此操作以原子方式验证futex地址   uaddr仍然包含值val,并等待FUTEX_WAKE等待   这个futex地址。如果超时参数是   非NULL,其内容描述了等待的最长持续时间,   否则就是无限的。参数uaddr2和val3是   忽略。

因此,从这个描述我可以说,如果一个互斥锁被锁定,那么一个线程将睡眠而不是主动等待。并且它会一直睡到调用等于FUTEX_WAKE的futex。