您的位置:首页 > 其它

futex

2017-03-04 20:53 337 查看
Futex是fast userspace mutex的缩写,Futex按英文翻译过来就是快速用户空间互斥体。其设计思想其实 不难理解,在传统的Unix系统中,System V IPC(inter process communication),如 semaphores, msgqueues, sockets还有文件锁机制(flock())等进程间同步机制都是对一个内核对象操作来完成的,这个内核对象对要同步的进程都是可见的,其提供了共享 的状态信息和原子操作。当进程间要同步的时候必须要通过系统调用(如semop())在内核中完成。可是经研究发现,很多同步是无竞争的,即某个进程进入
互斥区,到再从某个互斥区出来这段时间,常常是没有进程也要进这个互斥区或者请求同一同步变量的。但是在这种情况下,这个进程也要陷入内核去看看有没有人 和它竞争,退出的时侯还要陷入内核去看看有没有进程等待在同一同步变量上。这些不必要的系统调用(或者说内核陷入)造成了大量的性能开销。为了解决这个问 题,Futex就应运而生,Futex是一种用户态和内核态混合的同步机制。首先,同步的进程间通过mmap共享一段内存,futex变量就位于这段共享 的内存中且操作是原子的,当进程尝试进入互斥区或者退出互斥区的时候,先去查看共享内存中的futex变量,如果没有竞争发生,则只修改futex,而不
用再执行系统调用了。当通过访问futex变量告诉进程有竞争发生,则还是得执行系统调用去完成相应的处理(wait 或者 wake up)。简单的说,futex就是通过在用户态的检查,(motivation)如果了解到没有竞争就不用陷入内核了,大大提高了low-contention时候的效率。 Linux从2.5.7开始支持Futex。

Futex是一种用户态和内核态混合机制,所以需要两个部分合作完成,linux上提供了sys_futex系统调用,对进程竞争情况下的同步处理提供支持。

其原型和系统调用号为

#include <linux/futex.h>

#include <sys/time.h>

int futex (int *uaddr, int op, int val, const struct timespec *timeout,int *uaddr2, int val3);

#define __NR_futex              240        

虽然参数有点长,其实常用的就是前面三个,后面的timeout大家都能理解,其他的也常被ignore。

uaddr就是用户态下共享内存的地址,里面存放的是一个对齐的整型计数器。

op存放着操作类型。定义的有5中,这里我简单的介绍一下两种,剩下的感兴趣的自己去man futex

FUTEX_WAIT: 原子性的检查uaddr中计数器的值是否为val,如果是则让进程休眠,直到FUTEX_WAKE或者超时(time-out)。也就是把进程挂到uaddr相对应的等待队列上去。

FUTEX_WAKE: 最多唤醒val个等待在uaddr上进程。

在Bionc中,提供了两个函数来包装Futex系统调用。

extern int __futex_wait(volatile void *ftx, int val, const struct timespec *timeout);

extern int __futex_wake(volatile void *ftx, int count);

Bionc中还有两个类似的函数,它们的原型如下:

extern int  __futex_wake_ex(volatile void *ftx, int pshared, int val);

extern int  __futex_wait_ex(volatile void *ftx, int pshared, int val,

const struct timespec *timeout);

这两个函数比前面的多了一个参数pshared。pshared的值为true表示wake和wait操作是用于进程间的挂进和唤醒;值为false表示操作用于进程内线程的挂进和唤醒。当pshared的值为false时,执行Futex系统调用的操作码为:

FUTEX_WAIT|FUTEX_PRIVATE_FLAG,

FUTEX_WAKE|FUTEX_PRIVATE_FLAG

这样内核如果检测到操作有FUTEX_PRIVATE_FLAG标记,能以更快的速度执行挂起和唤醒操作。

__futex_wait和__futex_wake函数相当于pshared等于true的情况。

Android中有些模块还会使用下面的Futex函数:

extern int __futex_syscall3(volatile void *ftx, int op, int val);

extern int __futex_syscall4(volatile void *ftx, int op, int val,

const struct timespec *timeout);

__futex_syscall3()相当于__futex_wake(),而__futex_syscall4()相当于__futex_wait()。这两个函数与前面的区别是能指定操作码op做为参数。操作码可以是FUTEX_WAIT,FUTEX_WAKE或者它们和FUTEX_PRIVATE_FLAG的组合。

Android中操作码的定义如下:

#define FUTEX_WAIT         0

#define FUTEX_WAKE         1 

#ifndef FUTEX_PRIVATE_FLAG

#define FUTEX_PRIVATE_FLAG  128

#endif 

#ifndef FUTEX_WAIT_PRIVATE

#define FUTEX_WAIT_PRIVATE  (FUTEX_WAIT|FUTEX_PRIVATE_FLAG)

#endif 

#ifndef FUTEX_WAKE_PRIVATE

#define FUTEX_WAKE_PRIVATE  (FUTEX_WAKE|FUTEX_PRIVATE_FLAG)

#endif

FastMixer中使用syscall(__NR_futex, &mFastCaptureFutex, FUTEX_WAKE_PRIVATE, 1)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: