首页
论坛
课程
招聘
[原创]mutex实现与性能
2022-2-23 22:22 13794

[原创]mutex实现与性能

2022-2-23 22:22
13794

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

0x1、结论

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

 

结论如下:

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

0x2、mutex实现

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

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

0x3、实验过程

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

 

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

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

测试代码:

1
2
3
4
5
6
7
8
9
10
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时有系统调用)。

1
2
3
4
5
6
7
8
9
10
11
12
13
xjp@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、场景二:多线程加锁,有争抢

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
[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

搞定!

 

欢迎大家使用常用聊天软件关注、评论交流~
如果大家觉得有用,求点赞、转发~


【看雪培训】《Adroid高级研修班》2022年夏季班招生中!

最后于 2022-2-23 22:23 被assqqq编辑 ,原因: 忘写标题了
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回