brpc futex应用

分析环境为centos,还有其他的futex_wait_private实现,这里暂时忽略。

brpc中bthread主线程的等待操作wait_task使用futex_wait_private实现。

futex_wait_private的具体实现使用了系统调用SYS_futex。
SYS_futex的优势从名字“futex - fast user-space locking”就可以看的出来,详细实现相关后续自己阅读了解,暂时先明白用法。

futex_wait_private等在brpc中实现

inline int futex_wait_private(
    void* addr1, int expected, const timespec* timeout) {
    return syscall(SYS_futex, addr1, (FUTEX_WAIT | FUTEX_PRIVATE_FLAG),
                   expected, timeout, NULL, 0);
}

inline int futex_wake_private(void* addr1, int nwake) {
    return syscall(SYS_futex, addr1, (FUTEX_WAKE | FUTEX_PRIVATE_FLAG),
                   nwake, NULL, NULL, 0);
}

inline int futex_requeue_private(void* addr1, int nwake, void* addr2) {
    return syscall(SYS_futex, addr1, (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG),
                   nwake, NULL, addr2, 0);
}

futex说明:

NAME   futex - fast user-space locking

long futex(uint32_t *uaddr, int futex_op, uint32_t val,
                 const struct timespec *timeout,   /* or: uint32_t val2 */
                 uint32_t *uaddr2, uint32_t val3);
FUTEX_PRIVATE_FLAG (since Linux 2.6.22)
              This option bit can be employed with all futex operations.
              It tells the kernel that the futex is process-private and
              not shared with another process (i.e., it is being used
              for synchronization only between threads of the same
              process).  This allows the kernel to make some additional
              performance optimizations.

              As a convenience, <linux/futex.h> defines a set of
              constants with the suffix _PRIVATE that are equivalents of
              all of the operations listed below, but with the
              FUTEX_PRIVATE_FLAG ORed into the constant value.  Thus,
              there are FUTEX_WAIT_PRIVATE, FUTEX_WAKE_PRIVATE, and so
              on.
FUTEX_WAIT (since Linux 2.6.0)
              This operation tests that the value at the futex word
              pointed to by the address uaddr still contains the
              expected value val, and if so, then sleeps waiting for a
              FUTEX_WAKE operation on the futex word.  The load of the
              value of the futex word is an atomic memory access (i.e.,
              using atomic machine instructions of the respective
              architecture).  This load, the comparison with the
              expected value, and starting to sleep are performed
              atomically and totally ordered with respect to other futex
              operations on the same futex word.  If the thread starts
              to sleep, it is considered a waiter on this futex word.
              If the futex value does not match val, then the call fails
              immediately with the error EAGAIN.

              The purpose of the comparison with the expected value is
              to prevent lost wake-ups.  If another thread changed the
              value of the futex word after the calling thread decided
              to block based on the prior value, and if the other thread
              executed a FUTEX_WAKE operation (or similar wake-up) after
              the value change and before this FUTEX_WAIT operation,
              then the calling thread will observe the value change and
              will not start to sleep.
FUTEX_WAKE (since Linux 2.6.0)
              This operation wakes at most val of the waiters that are
              waiting (e.g., inside FUTEX_WAIT) on the futex word at the
              address uaddr.  Most commonly, val is specified as either
              1 (wake up a single waiter) or INT_MAX (wake up all
              waiters).  No guarantee is provided about which waiters
              are awoken (e.g., a waiter with a higher scheduling
              priority is not guaranteed to be awoken in preference to a
              waiter with a lower priority).

              The arguments timeout, uaddr2, and val3 are ignored.
FUTEX_REQUEUE (since Linux 2.6.0)
              This operation performs the same task as FUTEX_CMP_REQUEUE
              (see below), except that no check is made using the value
              in val3.  (The argument val3 is ignored.)

FUTEX_CMP_REQUEUE (since Linux 2.6.7)
              This operation first checks whether the location uaddr
              still contains the value val3.  If not, the operation
              fails with the error EAGAIN.  Otherwise, the operation
              wakes up a maximum of val waiters that are waiting on the
              futex at uaddr.  If there are more than val waiters, then
              the remaining waiters are removed from the wait queue of
              the source futex at uaddr and added to the wait queue of
              the target futex at uaddr2.  The val2 argument specifies
              an upper limit on the number of waiters that are requeued
              to the futex at uaddr2.

内容参考:https://man7.org/linux/man-pages/man2/futex.2.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容