c - 内核中的 Futex 和阻塞

标签 c multithreading linux-kernel mutex futex

我正在阅读一些文档并尝试一些发出 futex 的代码示例。 Linux 中的系统调用。我读到如果 thread_a 获得了互斥锁使用 FUTEX_LOCK_PI ,并说如果另一个线程 thread_b试图获得相同的,后者( thread_b )在内核中被阻止。

“在内核中阻塞”究竟是什么意思?是不是执行了thread_b在用户空间不恢复?在以下示例中,第二个线程似乎也在系统调用之后发出 printf。这不是表明它没有在内核中被阻塞吗?我错过了什么?

/*
 * This example demonstrates that when futex_lock_pi is called twice, the
 * second call is blocked inside the kernel.
 */

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

int mutex = 0;

#define  __NR_futex          240
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
#define FUTEX_FD 2
#define FUTEX_REQUEUE 3
#define FUTEX_CMP_REQUEUE 4
#define FUTEX_WAKE_OP 5
#define FUTEX_LOCK_PI 6
#define FUTEX_UNLOCK_PI 7
#define FUTEX_TRYLOCK_PI 8
#define FUTEX_WAIT_REQUEUE_PI 11
#define FUTEX_CMP_REQUEUE_PI  12


void *thread(void *arg) {
  int ret = 0;
  pid_t tid = gettid();
  printf("Entering thread[%d]\n", tid);

  ret = syscall(__NR_futex, &mutex, FUTEX_LOCK_PI, 1, NULL, NULL, 0);
  printf("Thread %d returned from kernel\n", tid);
  printf("Value of mutex=%d\n", mutex);
  printf("Return value from syscall=%d\n", ret);
}

int main(int argc, const char *argv[]) {
  pthread_t t1, t2;

  if (pthread_create(&t1, NULL, thread, NULL)) {
    printf("Could not create thread 1\n");
    return -1;
  }

  if (pthread_create(&t2, NULL, thread, NULL)) {
    printf("Could not create thread 2\n");
    return -1;
  }

  // Loop infinitely
  while ( 1 ) { }

  return 0;
}

输出可以在下面找到:-
Entering thread[952]
Thread 952 returned from kernel
Entering thread[951]
Value of mutex=-2147482696
Return value from syscall=0
Thread 951 returned from kernel
Value of mutex=-1073740873
Return value from syscall=0

最佳答案

在内核中阻塞意味着线程处于 sleep 状态,直到事件将其唤醒,在您的情况下,事件是可用的互斥锁。

我改变了一点你的代码来说明:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/syscall.h>

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void *thread(void *unused) {
  printf("Entering thread %d\n", syscall(SYS_gettid));

  pthread_mutex_lock(&mutex);

  sleep(2);

  pthread_mutex_unlock(&mutex);

  return NULL;
}

int main(int argc, const char *argv[]) {
  pthread_t t1, t2;

  printf("using mutex @%p\n", &mutex);

  if (pthread_create(&t1, NULL, thread, &t1)) {
    printf("Could not create thread 1\n");
    return -1;
  }

  if (pthread_create(&t2, NULL, thread, &t2)) {
    printf("Could not create thread 2\n");
    return -1;
  }

  pthread_join(t1, NULL);
  pthread_join(t2, NULL);

  return 0;
}

代码基本相同,但我明确使用了 pthread 库的互斥锁。

如果我用 strace 运行这段代码,我会得到:
using mutex @0x6010a0
Process 19688 attached
Entering thread 19688
Process 19689 attached
Entering thread 19689
[pid 19689] futex(0x6010a0, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid 19688] futex(0x6010a0, FUTEX_WAKE_PRIVATE, 1) = 1
[pid 19689] <... futex resumed> )       = 0
[pid 19688] +++ exited with 0 +++
[pid 19689] futex(0x6010a0, FUTEX_WAKE_PRIVATE, 1) = 0
[pid 19689] +++ exited with 0 +++
+++ exited with 0 +++

您可能会注意到,我们没有看到第一个线程使用互斥锁,但是我们可以看到下一个线程在等待 futex (FUTEX_WAIT_PRIVATE)。这是因为在获取互斥锁时不会调用 futex。

但是你可以看到第一个线程(这里的 id 为 19688)最终调用了 futex(FUTEX_WAKE_PRIVATE),它告诉内核在 utex 空闲的时候唤醒另一个线程。

你可能已经注意到第一个调用[pid 19689] futex(0x6010a0, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>未完成,这意味着进程被挂起,等待内核完成工作并交还手。
然后[pid 19689] <... futex resumed> ) = 0调用最终完成的草图(显然是因为互斥锁被释放了)

关于c - 内核中的 Futex 和阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33208589/

相关文章:

Java:如何构建可扩展的Job处理机制

python - 如何使用 ROS-SMACH FSM 正确传递(可变)对象

multithreading - Linux内核线程没有地址空间

linux-kernel - 有人可以帮我替换 block 设备驱动程序上的 “lock_kernel”吗?

c - 如何在linux中模拟socket/tcp编程的异常情况,例如终止连接的一侧?

python - 使用 cmake 构建 Python 共享对象绑定(bind),这取决于外部库

linux - 在 Linux 上获取进程和线程关联掩码

linux - 各种CPU掩码之间的区别 - Linux内核

c - C 中的指针 (while(*s1++ = *s2++))

c++ - C++中extern "C"有什么作用?