linux内核futex快速用户空间互斥体简介
futex内核同步
futex快速用户空间互斥体,用来给上层应用构建更高级别的同步机制,是实现信号量和锁的基础。
进程间通信,管道、消息队列、信号量、共享内存、套接字、信号。
使用信号量(semget()、semop()、semctl())进程间通信,是通过系统调用在内核中完成的。
进程要陷入内核去看看有没有人和它竞争,退出的时侯还要陷入内核去看看有没有进程等待在同一同步变量上。这些不必要的系统调用造成了大量的性能开销。
所以出现了futex,futex是一种用户态和内核态混合的同步机制。通过在用户态检查,没有竞争就不陷入内核执行系统调用了。访问futex变量通知进程有竞争发生,则执行系统调用去完成相应的操作。
futex系统调用
sys_futex系统调用,对进程竞争情况下的同步处理提供支持。
futex同步
进程、线程可以利用futex来进行同步。
futex同步操作都应该从用户空间开始,创建一个futex整形同步变量。
同步的进程间通过mmap共享一段内存,futex变量就位于这段共享的内存中,执行原子操作。
进程尝试持有锁或者要进入互斥区的时候,futex同步变量减1。如果同步变量变为0,则没有竞争发生, 进程照常执行。如果为负意味有竞争发生,系统调用的futex_wait休眠当前进程。
当进程释放锁或者要离开互斥区的时候,futex同步变量加1。如果同步变量由0变成1,则没有竞争发生,进程照常执行。如果为负意味有竞争发生,系统调用的futex_wake唤醒一或多个等待进程。
futex系统调用案例
一个进程在等待某个信号的时候,最终会通过系统调用进入到futex。
系统调用有6个参数,上层应用在等待一个信号量的时候,给op这个参数传递的FUTEX_WAIT_BITSET,代码流程:
// kernel/futex.c
SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
struct __kernel_timespec __user *, utime, u32 __user *, uaddr2,
u32, val3) {
...
return do_futex(... op, ...);
}
long do_futex(...int op,...) {
int cmd = op & FUTEX_CMD_MASK;
switch (cmd) {
case FUTEX_WAIT_BITSET:
return futex_wait(uaddr, flags, val, timeout, val3);
...
}
...
}
进程系统调用futex_wait时,会将自己设置为睡眠状态,进行一次进程调度。
// kernel/futex.c
static int futex_wait(...) {
...
futex_wait_queue_me(...);
...
}
// kernel/futex.c
static void futex_wait_queue_me(...) {
...
// 调用futex的进程变为睡眠状态
set_current_state(TASK_INTERRUPTIBLE);
...
freezable_schedule();
...
}
// include/linux/freezer.h
static inline void freezable_schedule(void) {
...
schedule();
...
}
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)