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
搞定!
东北码农,全网同名,欢迎大家使用常用聊天软件关注、评论交流~
如果大家觉得有用,求点赞、转发~