Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C Futexes和内核中的阻塞_C_Multithreading_Linux Kernel_Mutex_Futex - Fatal编程技术网

C Futexes和内核中的阻塞

C Futexes和内核中的阻塞,c,multithreading,linux-kernel,mutex,futex,C,Multithreading,Linux Kernel,Mutex,Futex,我正在阅读一些文档,并尝试一些在Linux中发出futex系统调用的代码示例。我读到,如果一个互斥锁是由thread\u a使用FUTEX\u LOCK\u PI获取的,并且如果另一个线程thread\u b试图获取相同的互斥锁,则后者(thread\u b)在内核中被阻塞 “在内核中阻塞”的确切含义是什么?是不是用户空间中的线程b的执行没有恢复?在下面的示例中,第二个线程似乎也在系统调用之后发出printf。这不意味着它在内核中没有被阻塞吗?我错过了什么 /* * This example

我正在阅读一些文档,并尝试一些在Linux中发出
futex
系统调用的代码示例。我读到,如果一个互斥锁是由
thread\u a
使用
FUTEX\u LOCK\u PI
获取的,并且如果另一个线程
thread\u b
试图获取相同的互斥锁,则后者(
thread\u b
)在内核中被阻塞

“在内核中阻塞”的确切含义是什么?是不是用户空间中的
线程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;
}

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

我对您的代码做了一些修改,以说明:

#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\u mutex\u t mutex=pthread\u mutex\u初始值设定项;
空心*螺纹(空心*未使用){
printf(“正在输入线程%d\n”,syscall(SYS\u getId));
pthread_mutex_lock(&mutex);
睡眠(2);
pthread_mutex_unlock(&mutex);
返回NULL;
}
int main(int argc,const char*argv[]{
pthread_t t1,t2;
printf(“使用互斥体@%p\n”,&mutex);
if(pthread_create(&t1,NULL,thread,&t1)){
printf(“无法创建线程1\n”);
返回-1;
}
if(pthread_create(&t2,NULL,thread,&t2)){
printf(“无法创建线程2\n”);
返回-1;
}
pthread_join(t1,NULL);
pthread_join(t2,NULL);
返回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 +++
使用互斥体@0x6010a0
过程19688附后
进入线程19688
过程19689附后
进入线程19689
[pid 19689]futex(0x6010a0,futex_WAIT_PRIVATE,2,空
[pid 19688]futex(0x6010a0,futex_WAKE_PRIVATE,1)=1
[pid 19689])=0
[pid 19688]+++以0退出+++
[pid 19689]futex(0x6010a0,futex_WAKE_PRIVATE,1)=0
[pid 19689]+++已用0退出+++
+++以0退出+++
您可能会注意到,我们没有看到第一个线程使用互斥锁,但我们可以看到下一个线程为等待调用futex(futex_WAIT_PRIVATE)。这是因为在使用互斥时futex不会被调用

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

你可能已经注意到第一个电话
[pid 19689]futex(0x6010a0,futex\u WAIT\u PRIVATE,2,NULL
是未完成的,这意味着进程被挂起,等待内核完成任务并返回手。
然后
[pid 19689])=0
表示调用最终完成(显然是因为互斥被释放了)

您使用的,它实际上与互斥一起工作(这就是futex操作名称中的
LOCK
子字符串的原因)。在该模式下,futex值转换方案是完全定义的,不依赖于
val
val2
系统调用的参数。处于解锁状态的futex值必须为0。另外,在PI模式下,内核检查与存储在futex中的
tid
值对应的进程(线程)是否存在,并实际访问它以执行优先级反转。据我所知,若futex的所有者退出,互斥锁将被视为未锁定。尝试在线程函数的末尾添加
sleep()
,并检查第二个线程是否在第一个线程(futex所有者)睡眠时从
futex()
调用返回。(这不应该发生)。您将互斥锁初始化为什么?你能给我们完整的、可编译的代码吗?@DavidSchwartz我已经将代码更新为完整的、可编译的,谢谢。但是你的代码和输出不匹配。您是否可以显示此代码的输出,并理想地添加syscall返回值?
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 +++