mutex实现与性能初探

大家好,我是东北码农。
今天讲讲工作中的事吧,领导要求调研一个事,mutex性能如何?mutex无竞争时和有竞争时效率如何?

0x1、结论

我和领导汇报时,都习惯先说结论,领导可以很容易抓住重点,如果感兴趣就继续看。

结论如下:

  • 没有争抢时,不进入内核态。性能与自旋锁类似。
  • 有争抢时,没抢到,进入内核态等待唤醒。

0x2、mutex实现

mutex实现时,分用户态部分和内核态部分,分别承担不同的功能:

  • 用户态:使用test and set来测试是否可以抢到锁。
  • 内核态:使用futex系统调用来等待和唤醒。

0x3、实验过程

使用我们的老朋友strace命令来观察抢锁时的系统调用情况。

strace使用可以参考前面的文章:
如何使用strace
动手实现一个strace

0x31、场景一:单线程加锁,无争抢

测试代码:

std::mutex g_lock;
void test_no_race()
{
    for(int i = 0;i < 10;++i)
    {
        g_lock.lock();
        usleep(100*1000);
        g_lock.unlock();
    }
}

strace看一下,lock unlock无系统调用(只有sleep时有系统调用)。

***@xxx:~/code/case/case30_c11_fence$ strace -f ./a.out
。。。
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
。。。

0x31、场景二:多线程加锁,有争抢

测试代码:

std::mutex g_lock;

void test_no_race()
{
    for(int i = 0;i < 10;++i)
    {
        g_lock.lock();
        usleep(100*1000);
        g_lock.unlock();
    }
}

void test_race()
{
    std::thread t1(test_no_race);
    std::thread t2(test_no_race);
    
    t1.join();
    t2.join();
}

用strace看一下,此时会大量调用futex 系统调用,来等待(FUTEX_WAIT_PRIVATE)和唤醒(FUTEX_WAKE_PRIVATE)。

[pid   552] futex(0x7f61977959d0, FUTEX_WAIT, 553, NULL <unfinished ...>
[pid   554] <... set_robust_list resumed>) = 0
[pid   554] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   553] <... clock_nanosleep resumed>NULL) = 0
[pid   553] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid   554] <... futex resumed>)        = 0
[pid   553] <... futex resumed>)        = 1
[pid   554] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   553] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   554] <... clock_nanosleep resumed>NULL) = 0
[pid   554] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 1
[pid   553] <... futex resumed>)        = 0
[pid   554] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   553] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   554] <... clock_nanosleep resumed>NULL) = 0
[pid   554] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 1
[pid   553] <... futex resumed>)        = 0
[pid   554] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   553] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   554] <... clock_nanosleep resumed>NULL) = 0
[pid   554] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 1
[pid   553] <... futex resumed>)        = 0
[pid   554] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   553] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   554] <... clock_nanosleep resumed>NULL) = 0
[pid   554] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 1
[pid   553] <... futex resumed>)        = 0
[pid   554] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   553] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   554] <... clock_nanosleep resumed>NULL) = 0
[pid   554] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 1
[pid   553] <... futex resumed>)        = 0
[pid   554] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   553] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   554] <... clock_nanosleep resumed>NULL) = 0
[pid   554] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 1
[pid   554] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   553] <... futex resumed>)        = 0
[pid   553] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   554] <... clock_nanosleep resumed>NULL) = 0
[pid   554] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 1
[pid   553] <... futex resumed>)        = 0
[pid   553] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   554] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   553] <... clock_nanosleep resumed>NULL) = 0
[pid   553] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 1
[pid   554] <... futex resumed>)        = 0
[pid   554] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   553] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
[pid   553] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid   554] <... futex resumed>)        = 0
[pid   553] <... futex resumed>)        = 1
[pid   554] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   553] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   554] <... clock_nanosleep resumed>NULL) = 0
[pid   554] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 1
[pid   553] <... futex resumed>)        = 0
[pid   554] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   553] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   554] <... clock_nanosleep resumed>NULL) = 0
[pid   554] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 1
[pid   553] <... futex resumed>)        = 0
[pid   554] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   553] futex(0x560716857060, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid   554] <... clock_nanosleep resumed>NULL) = 0
[pid   554] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 1
[pid   553] <... futex resumed>)        = 0
[pid   554] mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0 <unfinished ...>
[pid   553] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000},  <unfinished ...>
[pid   554] <... mmap resumed>)         = 0x7f618e794000
[pid   554] munmap(0x7f618e794000, 25608192) = 0
[pid   554] munmap(0x7f6194000000, 41500672) = 0
[pid   554] mprotect(0x7f6190000000, 135168, PROT_READ|PROT_WRITE) = 0
[pid   554] madvise(0x7f6196794000, 8368128, MADV_DONTNEED) = 0
[pid   554] exit(0)                     = ?
[pid   554] +++ exited with 0 +++
[pid   553] <... clock_nanosleep resumed>NULL) = 0
[pid   553] futex(0x560716857060, FUTEX_WAKE_PRIVATE, 1) = 0
[pid   553] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
[pid   553] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
[pid   553] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
[pid   553] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
[pid   553] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0
[pid   553] clock_nanosleep(CLOCK_REALTIME, 0, {tv_sec=0, tv_nsec=100000000}, NULL) = 0

搞定!

东北码农,全网同名,欢迎大家使用常用聊天软件关注、评论交流~
如果大家觉得有用,求点赞、转发~

posted @ 2022-02-23 22:29  东北码农  阅读(440)  评论(0编辑  收藏  举报