• Linux进程同步机制-Futex 2010-03-20 23:11:00
    引子在编译2.6内核的时候,你会在编译选项中看到[*] Enable futex support这一项,上网查,有的资料会告诉你"不选这个内核不一定能正确的运行使用glibc的程序",那futex是什么?和glibc又有什么关系呢?...

    引子
    在编译2.6内核的时候,你会在编译选项中看到[*] Enable futex support这一项,上网查,有的资料会告诉你"不选这个内核不一定能正确的运行使用glibc的程序",那futex是什么?和glibc又有什么关系呢?

    1. 什么是Futex
    Futex 是Fast Userspace muTexes的缩写,由Hubertus Franke, Matthew Kirkwood, Ingo Molnar and Rusty Russell共同设计完成。几位都是linux领域的专家,其中可能Ingo Molnar大家更熟悉一些,毕竟是O(1)调度器和CFS的实现者。

    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。

    2. 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上进程。
       
        可见FUTEX_WAIT和FUTEX_WAKE只是用来挂起或者唤醒进程,当然这部分工作也只能在内核态下完成。有些人尝试着直接使用futex系统调 用来实现进程同步,并寄希望获得futex的性能优势,这是有问题的。应该区分futex同步机制和futex系统调用。futex同步机制还包括用户态 下的操作,我们将在下节提到。
           
    3. Futex同步机制
    所有的futex同步操作都应该从用户空间开始,首先创建一个futex同步变量,也就是位于共享内存的一个整型计数器。
    当 进程尝试持有锁或者要进入互斥区的时候,对futex执行"down"操作,即原子性的给futex同步变量减1。如果同步变量变为0,则没有竞争发生, 进程照常执行。如果同步变量是个负数,则意味着有竞争发生,需要调用futex系统调用的futex_wait操作休眠当前进程。
    当进程释放锁或 者要离开互斥区的时候,对futex进行"up"操作,即原子性的给futex同步变量加1。如果同步变量由0变成1,则没有竞争发生,进程照常执行。如 果加之前同步变量是负数,则意味着有竞争发生,需要调用futex系统调用的futex_wake操作唤醒一个或者多个等待进程。

    这里的原子性加减通常是用CAS(Compare and Swap)完成的,与平台相关。CAS的基本形式是:CAS(addr,old,new),当addr中存放的值等于old时,用new对其替换。在x86平台上有专门的一条指令来完成它: cmpxchg。

    可见: futex是从用户态开始,由用户态和核心态协调完成的。

    4. 进/线程利用futex同步
    进程或者线程都可以利用futex来进行同步。
    对于线程,情况比较简单,因为线程共享虚拟内存空间,虚拟地址就可以唯一的标识出futex变量,即线程用同样的虚拟地址来访问futex变量。
    对 于进程,情况相对复杂,因为进程有独立的虚拟内存空间,只有通过mmap()让它们共享一段地址空间来使用futex变量。每个进程用来访问futex的 虚拟地址可以是不一样的,只要系统知道所有的这些虚拟地址都映射到同一个物理内存地址,并用物理内存地址来唯一标识futex变量。
       
    小结:
    1. Futex变量的特征:1)位于共享的用户空间中 2)是一个32位的整型 3)对它的操作是原子的
    2. Futex在程序low-contention的时候能获得比传统同步机制更好的性能。
    3. 不要直接使用Futex系统调用。
    4. Futex同步机制可以用于进程间同步,也可以用于线程间同步。

    下面给出一份示例代码。

     

     

    root:/home/ftpuser/ipc#g++ -o  futex -lrt futex.cc     
    root:/home/ftpuser/ipc#./futex
    parent start waiting
    Child 2825: start
    wake up parent
    parent end waiting

    There is 3 item in the shm
    1: Nellson
    2: Daisy
    3: Robbie

    Parent 2824 get child status:0

    展开全文
  • 进程 一、进程的存储器安排 这是《UNIX环境高级编程》中介绍的典型存储器安排,但现实也不一定非要如此。对于c/c++来说,数据的存储方式还是认为3种:堆、栈、全局数据区(包括全局数据、静态数据、常量)。 二、...
  • Linux进程同步机制 2019-11-23 16:38:43
    1. 互斥锁 主要用在线程间,虽然通过改变它的属性可以支持进程间,但并非所有平台都支持,所以应当仅在线程间用。 2. 条件变量 ...信号量设计为进程间通信机制,所以应当用在进程间。 (1)最常...
  • linux进程间同步 2016-03-17 14:30:55
    为了能够有效的控制多个进程之间的沟通过程,OS必须提供一定的同步机制保证进程之间不会自说自话而是有效的协同工作。比如在共享内存的通信方式中,两个或者多个进程都要对共享的内存进行数据写入,那么怎么才能保证...
  • 同步与互斥是进程间的制约关系, 同步: 是为了保证临界资源的时序的可控性,安全性。是进程间由于相互合作引起的直接制约关系。 互斥: 是为了保证对临界资源同一时间的唯一访问性。是进程间由于共享资源引起的...
  • linux进程间同步机制/方式和进程间通信的方法 Linux进程同步的方式:信号量、阻塞、异步IO、事件、变量锁  Linux下进程通信的七种方法:管道(pipe),命名管道(FIFO),内存映射(mapped memeory),消息队列...
  • 进程同步:是指一组并发的进程互相合作互相等待,使得各进程按照一定的顺序执行的过程叫做进程同步同步与互斥的区别:同步时信号量初始值为0,互斥时信号量初始值大于0。 解释:如果用信号量互斥的话,必须是...
  • 一、linux进程间通讯实现方式有很多种。包含管道、信号、共享内存、套接字 而 管道、信号、共享内存 这三种方式只适用于同一台设备间进程间通讯。套接字可以跨设备进行进程间通讯 1.管道机制 管道机制是...
  • linux下的多个进程间的通信机制叫做IPC(Inter-Process Communication),它是多个进程之间相互沟通的一种方法。在linux下有多种进程间通信的方法:半双工管道、命名管道、消息队列、信号、信号量、共享内存、内存...
  • 进程间通信和同步 2018-02-01 10:21:01
    管道式Linux系统中最古老的进程间通信机制,这里所说的管道是指无名管道(PIPE),它可用于具有亲缘关系进程间的通信.有名管道(FIFO)克服了管道没有名字的限制,因此,除了具有管道所有具有的功能外,它还允许无亲缘关系
  • Linux进程同步方法 2019-03-17 18:57:32
    进程同步的四种方法 1、临界区(Critical Section):通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。 优点:保证在某一时刻只有一个线程能访问数据的简便办法 缺点:虽然临界区同步速度...
  • 进程间通信概述进程通信的目的 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或...
  • 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信; 信号(Signal):信号是比较...
  • 共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式, 因为进程可以直接读写内存,而不需要任何 数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则 ...
  • Linux中的同步机制 2011-10-25 16:35:12
    Linux中的同步机制(一)--Futex 引子 在编译2.6内核的时候,你会在编译选项中看到[*] Enable futex support这一项,上网查,有的资料会告诉你"不选这个内核不一定能正确的运行使用glibc的程序",那futex是什
  • 1、一个进程中的线程与另外一个进程中的线程通信,由于两个线程只能访问自己所属进程的地址空间和资源,故等同于进程间的通信。 2、同一个进程中的两个线程进行通信。本文说的就是第二种情况。 关于进程间通信...
  • Linux内核中的同步机制 2018-08-26 15:54:06
    本文介绍Linux内核中的一些同步机制,通过本文,希望读者能够明白以下几点: 什么是同步 为什么要同步 同步的几种手段 1.什么是同步? 与其解释什么是同步,倒不如告诉读者同步的由来。在Linux内核中,同步技术...
  • 基本概念: 大部分同学都知道线程同步进程同步的概念, 线程同步:多线程编程中,解决共享资源冲突的问题 ...首先我们知道,linux下每个进程都有自己的独立进程空间,假设A进程和B进程各有一个互斥锁,这个锁放
  • 一、进程/线程间同步机制。 临界区、互斥区、事件、信号量四种方式 临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)的区别 1、临界区:通过对多线程的串行化来访问公共资源或一段...
  • Linux环境进程间通信(五): 共享内存(上) 共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以...
1 2 3 4 5 ... 20
收藏数 56,134
精华内容 22,453