C Futexes和内核中的阻塞
我正在阅读一些文档,并尝试一些在Linux中发出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
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 +++