futex函数_fulfilment和fulfillment

futex函数_fulfilment和fulfillment#include<linux/futex.h>#include<sys/time.h>intfutex(int*uaddr,intfutex_op,intval,     conststructtimespec*timeout,/*or:uint32_tval2*/     int*uaddr2,intval3…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

 

#include <linux/futex.h>

#include <sys/time.h>

int futex(int *uaddr, int futex_op, int val,

      const struct timespec *timeout, /* or: uint32_t val2 */

      int *uaddr2, int val3);

DESCRIPTION:

  futex()系统调用提供了一种方法用于等待某个特定条件的发生。一种典型的应用是在共享内存同步中作为阻塞装置。当使用futex时,绝大部分同步操作都在用户态完成,一个用户态程序只有在有可能阻塞一段较长的时间等待条件的发生时才使用futex。其他的futex操作可以用来唤醒等待特定条件发生的任何进程或线程。

  一个futex是一个32位的值,它的地址通过futex()传入,futexs在所有的平台上都是32位的(包括64位系统上),所有的futex操作都是在这个值上。为了在多个进程间共享futex,futex位于由mmap或者shmat创建的一块共享内存上(这种情况下,futex值在不同的进程上可能位于不同的虚拟地址,但这些虚拟地址都指向相同的物理地址)。在多线程程序中,将futex值放到一个所有线程共享的全局变量中就可以了。

  当执行一个futex操作请求阻塞一个线程时,只有在 *uaddr == val 时,内核才会执行阻塞操作,这个操作中的所有步骤(1. 导入*uaddr的值; 2. 比较; 3.阻塞线程)将原子的执行,并且当其他线程在同一个futex值上并行操作时所有的步骤不会乱序。

  futex的一种使用方式是用来实现锁,锁的状态(acquired or not acquired)可以用在共享内存中的原子标志表示。在非竞争的情况下,线程可以通过原子操作访问和修改锁的状态(这些操作全部在用户态操作,内核不会保存任何关于锁的状态)。从另一方面来说,另一个线程可能无法获取锁(因为锁已经被某个线程获取),这个线程将通过如下这种方式执行futex()等待操作:

atomic<int> lock; // lock : 0. 锁未被获取 1.锁被获取
futex(&lock, FUTEX_WAIT, 1, NULL, NULL, NULL);

  futex(FUTEX_WAIT)将会检测lock的值,只有在等于1时才阻塞线程。当线程释放锁时,该线程必须首先重置锁的状态,然后执行futex操作唤醒阻塞在lock上的线程。

  注意使用futex并没有显示的初始化和销毁操作,内核只有在一个指定的futex值上执行futex操作时(例如FUTEX_WAIT)才会维护futex数据。

 

Arguments(参数):

  uaddr指向futex值,在所有的平台上,futex值是一个4字节的整数并且必须4字节对齐。

  对于某些阻塞操作,timeout参数是一个指向timespec结构的指针,表明了操作的超时时间。然而,在其他的某些操作下,它的最低4字节被作为一个整数值,这个整数值的含义因futex操作的不同而不同,对于这些操作来说,内核会将timeout值转换为unsigned long,然后转换为uint32_t,在接下来的说明中,它将表示为val2。

  在需要的时候,uaddr2是指向第二个futex值的指针,val3的解释将依赖于具体的操作。

Futex operations (操作) :

  futex_op参数包含两个部分:1.操作类型 2.标志选项(影响操作行为)。

  FUTEX_PRIVATE_FLAG (since Linux 2.6.22)

    这个标志选项可以用在所有的futex操作中,它告诉内核这个futex是进程内的,不和其他进程共享(它只能用来同步同一个进程内的线程),这样内核可以做一些额外的优化。

  FUTEX_CLOCK_REALTIME (since Linux 2.6.28)

    这个标志选项只能用在FUTEX_WAIT_BITSET FUTEX_WAIT_REQUEUE_PI 操作中,如果设置了这个标志选项,内核会将timeout视作基于CLOCK_REALTIME 的绝对时间。如果没有设置这个标志,则内核将它视作基于CLOCK_MONOTONIC的相对时间。

 

  futex操作包含下面的几种:

  FUTEX_WAIT (since Linux 2.6.0)

  本操作会检查*uaddr是否等于val,如果相等的话,则睡眠等待在uaddr上的FUTEX_WAKE 操作,如果线程开始睡眠,则它被认为是这个futex值上一个等待者。如果两者不相等,则操作失败并返回 error EAGAIN。比较*uaddr和val的目的是为了避免丢失唤醒。

  如果timeout参数不为NULL,则它指定了等待的超时时间(根据CLOCK_MONOTONIC测量得出)。

 

  FUTEX_WAKE (since Linux 2.6.0)

  本操作会唤醒最多val个等待者,绝大部分情况下,val的值为1(只唤醒一个等待者)或INT_MAX(唤醒所有的等待者) 。注意没有任何机制保证一定唤醒某些特定的等待者(比如被认为是高优先级的等待者)

  参数timeout, uaddr2, val3将被忽略。

 

  FUTEX_REQUEUE (since Linux 2.6.0)

  本操作和下面的 FUTEX_CMP_REQUEUE 完成相同的功能,除了不检查val3 。(参数val3被忽略)

 

  FUTEX_CMP_REQUEUE (since Linux 2.6.7)

  本操作首先检查*uaddr是否等于val3,如果不相等,则返回error EAGAIN。否则的话,将唤醒最多val个等待者,如果等待者的数量大于val,则剩下的等待者则从uaddr的等待队列中移除,添加到uaddr2的等待队列中。val2参数指定了移动到uaddr2的等待者的最大数量。

  val的典型值为0或1,指定为INT_MAX是没有任何用处的,这将会使得FUTEX_CMP_REQUEUE 操作和 FUTEX_WAKE 操作相同。同样,val2的值通常为1或INT_MAX,指定为0是没有用的,这样将使得 FUTEX_CMP_REQUEUE  操作和  FUTEX_WAIT 操作相同。

  FUTEX_CMP_REQUEUE 是用来代替 FUTEX_REQUEUE 的,两者的不同点在于是否检查uaddr的值,这个检查操作可用来确保移除添加操作只在特定的条件下发生,这样就避免了某些 race condition。

  FUTEX_CMP_REQUEUE 和 FUTEX_REQUEUE 都可以用来避免 FUTEX_WAKE 可能产生的“线程惊群”现象。考虑下面的情况,多个线程在等待B(使用futex实现的等待队列):

lock(A)
while (!check_value(V)) {
      unlock(A);
      block_on(B);
      lock(A);
};
unlock(A);

  如果一个线程使用 FUTEX_WAKE 唤醒 B上的所有线程,则它们会全部尝试获取锁 A,然而在这种情况下唤醒所有的线程时徒劳的,因为除了一个线程之外其他的线程又全部阻塞在 A 上,相比之下,REQUEUE 操作可以唤醒一个等待线程然后将剩下的等待线程移动到 A 下,当线程解锁 A时其他的线程可以继续执行。

转载于:https://www.cnblogs.com/0x4141/p/5203361.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/191169.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • export命令什么意思_report函数

    export命令什么意思_report函数一个变量创建时,它不会自动地为在它之后创建的shell进程所知。而命令export可以向后面的shell传递变量的值。当一个shell脚本调用并执行时,它不会自动得到原为脚本(调用者)里定义的变量的访问权,除非这些变量已经被显式地设置为可用。export命令可以用于传递一个或多个变量的值到任何后继脚本。    —-《UNIX教程》

  • 2018年强势推荐区块链产品项目:流量魔盒详细操作攻略[通俗易懂]

    流量魔盒概述    在日常生活中,我们使用流量的方式其实都不是100%正确。例如微信,每使用一段时间就会产生大量的缓存垃圾,我们只有去清理掉缓存垃圾才能使我们的微信操作更流畅。    当我们使用了1G的流量,必定会产生一定量的缓存,流量魔盒把流量缓存统一、归集、上传、累计每个用户的缓存转化为真实流量作为实际应用,合理利用资源,把产生的流量缓存变成我们的财富。 注册地址https:…

  • (怪盗基德的滑翔翼)(最长上升子序列)[通俗易懂]

    (怪盗基德的滑翔翼)(最长上升子序列)[通俗易懂]原题链接怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。不得已,怪盗基德只能操作受损的滑翔翼逃脱。假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向

  • 高级java面试题及答案_java高级面试题大汇总

    高级java面试题及答案_java高级面试题大汇总一、参考资料不容错过的Java高级面试题_帝都的雁的博客-CSDN博客_java高级面试题java面试题汇总(上)_Oliverfly1的博客-CSDN博客_java面试题史上最全的中高级JAVA工程师面试题汇总有哪些?-知乎DevBooks:2021面试题,Java面试题、JVM面试题、多线程面试题、并发编程、设计模式面试题、SpringBoot面试题、SpringCloud面试题、MyBatis面试题-Gitee.com2021年Java高级面试题总结_m0_57699

  • smail指令参考「建议收藏」

    smail指令参考「建议收藏」DalvikopcodesAuthor: GaborPallerVxvaluesinthetabledenoteaDalvikregister.Dependingontheinstruction,16,256or64kregisterscanbeaccessed.Operationsonlonganddoublevalues

    2022年10月31日
  • QStringList 的学习笔记

    QStringList 的学习笔记因公司项目,开始学习QT,这里做一些学习笔记,一遍以后忘记了可以翻阅。笔记内容写的简单,勿怪。参考博客:https://blog.csdn.net/u013360881/article/details/52170487QStringList初始化QStringListqstrList;qstrList&amp;lt;&amp;lt;&quot;Android&quot;&amp;lt;&amp;lt;&quot;Qt

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号