-
-
[原创]mutex实现与性能
-
2022-2-23 22:22 14320
-
大家好,我是东北码农。
今天讲讲工作中的事吧,领导要求调研一个事,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 |
搞定!
欢迎大家使用常用聊天软件关注、评论交流~
如果大家觉得有用,求点赞、转发~
[2023春季班]2023,新的征程,脱壳机更新、iOS/eBPF、赠送云手机套装!一块裸板虚拟化五个容器云手机!3月25日起同时上调价格并赠送新设备!
最后于 2022-2-23 22:23
被assqqq编辑
,原因: 忘写标题了
赞赏
他的文章
[原创]mutex实现与性能
14321
[原创]原理+代码实战:SUID提权渗透
6225