mutex与spinlock
来源:互联网 发布:百度云网络异常 编辑:程序博客网 时间:2024/06/01 09:43
在写多线程的过程中,难免会遇到锁,一般使用的是mutex或者rwlock。
调试的过程中也发现,使用mutex的情况下,spinlock在perf会占有一定的比例。那么
1 mutex会在多大程度上影响程序的系能,什么情况下是值得使用的?
2 rwlock和mutex在实现上有什么不同?
3 spinlock和mutex有什么关系?
4 如何看待流行的非锁程序?性能会有提升吗?
从源码入手:mutex的接口使用,是pthread库中的pthread_mutex_lock,使用glibc-2.12.1,如下
/* Data structures for mutex handling. The structure of the attribute type is not exposed on purpose. */typedef union{ struct <span style="background-color: rgb(255, 102, 102);">__pthread_mutex_s</span> { int <span style="color:#ff6666;">__lock</span>; unsigned int __count; int __owner;#if __WORDSIZE == 64 unsigned int __nusers;#endif /* KIND must stay at this position in the structure to maintain binary compatibility. */ int <span style="color:#ff6666;">__kind</span>;#if __WORDSIZE == 64 int __spins; __pthread_list_t __list;# define __PTHREAD_MUTEX_HAVE_PREV1#else unsigned int __nusers; __extension__ union { int __spins; __pthread_slist_t __list; };#endif } __data; char __size[__SIZEOF_PTHREAD_MUTEX_T]; long int __align;} pthread_mutex_t;int<span style="background-color: rgb(255, 102, 102);">__pthread_mutex_lock </span>(mutex) pthread_mutex_t *mutex;{ assert (sizeof (mutex->__size) >= sizeof (mutex->__data)); unsigned int type = PTHREAD_MUTEX_TYPE (mutex); if (__builtin_expect (type & ~PTHREAD_MUTEX_KIND_MASK_NP, 0)) return __pthread_mutex_lock_full (mutex); pid_t id = THREAD_GETMEM (THREAD_SELF, tid); if (__builtin_expect (type, PTHREAD_MUTEX_TIMED_NP) == PTHREAD_MUTEX_TIMED_NP) { simple: /* Normal mutex. */ <span style="background-color: rgb(255, 102, 102);">LLL_MUTEX_LOCK </span>(mutex); assert (mutex->__data.__owner == 0); } else if (__builtin_expect (type == PTHREAD_MUTEX_RECURSIVE_NP, 1)) { /* Recursive mutex. */ /* Check whether we already hold the mutex. */ if (mutex->__data.__owner == id){ /* Just bump the counter. */ if (__builtin_expect (mutex->__data.__count + 1 == 0, 0)) /* Overflow of the counter. */ return EAGAIN; ++mutex->__data.__count; return 0;} /* We have to get the mutex. */ LLL_MUTEX_LOCK (mutex); assert (mutex->__data.__owner == 0); mutex->__data.__count = 1; } else if (__builtin_expect (type == PTHREAD_MUTEX_ADAPTIVE_NP, 1)) { if (! __is_smp)goto simple; if (LLL_MUTEX_TRYLOCK (mutex) != 0){ int cnt = 0; int max_cnt = MIN (MAX_ADAPTIVE_COUNT, mutex->__data.__spins * 2 + 10); do { if (cnt++ >= max_cnt){ LLL_MUTEX_LOCK (mutex); break;}#ifdef BUSY_WAIT_NOP BUSY_WAIT_NOP;#endif } while (LLL_MUTEX_TRYLOCK (mutex) != 0); mutex->__data.__spins += (cnt - mutex->__data.__spins) / 8;} assert (mutex->__data.__owner == 0); } else { assert (type == PTHREAD_MUTEX_ERRORCHECK_NP); /* Check whether we already hold the mutex. */ if (__builtin_expect (mutex->__data.__owner == id, 0))return EDEADLK; goto simple; } /* Record the ownership. */ mutex->__data.__owner = id;#ifndef NO_INCR ++mutex->__data.__nusers;#endif return 0;}#define LLL_MUTEX_LOCK(mutex) \ lll_cond_lock ((mutex)->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex))#define lll_cond_lock(futex, private) \ (void) \ ({ int ignore1, ignore2, ignore3; \ __asm __volatile (LOCK_INSTR "cmpxchgl %4, %2\n\t" \ "jnz 1f\n\t" \ ".subsection 1\n\t" \ ".type _L_cond_lock_%=, @function\n" \ "_L_cond_lock_%=:\n" \ "1:\tleaq %2, %%rdi\n" \ "2:\tsubq $128, %%rsp\n" \ "3:\tcallq <span style="background-color: rgb(255, 102, 102);">__lll_lock_wait</span>\n" \ "4:\taddq $128, %%rsp\n" \ "5:\tjmp 24f\n" \ "6:\t.size _L_cond_lock_%=, 6b-1b\n\t" \ ".previous\n" \ LLL_STUB_UNWIND_INFO_5 \ "24:" \ : "=S" (ignore1), "=D" (ignore2), "=m" (futex), \ "=a" (ignore3) \ : "1" (2), "m" (futex), "3" (0), "0" (private) \ : "cx", "r11", "cc", "memory"); \ })
void__lll_lock_wait (int *futex, int private){ if (*futex == 2) lll_futex_wait (futex, 2, private); while (atomic_exchange_acq (futex, 2) != 0) lll_futex_wait (futex, 2, private);}#define lll_futex_wait(futex, val, private) \ lll_futex_timed_wait(futex, val, NULL, private)#define lll_futex_timed_wait(futex, val, timeout, private) \ ({ \ register const struct timespec *__to __asm ("r10") = timeout; \ int __status; \ register __typeof (val) _val __asm ("edx") = (val); \ __asm __volatile ("syscall" \ : "=a" (__status) \ : "0" (SYS_futex), "D" (futex), \"S" (__lll_private_flag (FUTEX_WAIT, private)), \"d" (_val), "r" (__to) \ : "memory", "cc", "r11", "cx"); \ __status; \ })
glibc最终会调用系统调用futex,系统调用futex的源码在linux-2.6.38中如下:
SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,struct timespec __user *, utime, u32 __user *, uaddr2,u32, val3){struct timespec ts;ktime_t t, *tp = NULL;u32 val2 = 0;int cmd = op & FUTEX_CMD_MASK;if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || cmd == FUTEX_WAIT_BITSET || cmd == FUTEX_WAIT_REQUEUE_PI)) {if (copy_from_user(&ts, utime, sizeof(ts)) != 0)return -EFAULT;if (!timespec_valid(&ts))return -EINVAL;t = timespec_to_ktime(ts);if (cmd == FUTEX_WAIT)t = ktime_add_safe(ktime_get(), t);tp = &t;}/* * requeue parameter in 'utime' if cmd == FUTEX_*_REQUEUE_*. * number of waiters to wake in 'utime' if cmd == FUTEX_WAKE_OP. */if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE || cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)val2 = (u32) (unsigned long) utime;return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);}
其中调用了do_futex
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,u32 __user *uaddr2, u32 val2, u32 val3){int ret = -ENOSYS, cmd = op & FUTEX_CMD_MASK;unsigned int flags = 0;if (!(op & FUTEX_PRIVATE_FLAG))flags |= FLAGS_SHARED;if (op & FUTEX_CLOCK_REALTIME) {flags |= FLAGS_CLOCKRT;if (cmd != FUTEX_WAIT_BITSET && cmd != FUTEX_WAIT_REQUEUE_PI)return -ENOSYS;}switch (cmd) {case FUTEX_WAIT:val3 = FUTEX_BITSET_MATCH_ANY;case FUTEX_WAIT_BITSET:ret = futex_wait(uaddr, flags, val, timeout, val3);break;case FUTEX_WAKE:val3 = FUTEX_BITSET_MATCH_ANY;case FUTEX_WAKE_BITSET:ret = futex_wake(uaddr, flags, val, val3);break;case FUTEX_REQUEUE:ret = futex_requeue(uaddr, flags, uaddr2, val, val2, NULL, 0);break;case FUTEX_CMP_REQUEUE:ret = futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 0);break;case FUTEX_WAKE_OP:ret = futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);break;case FUTEX_LOCK_PI:if (futex_cmpxchg_enabled)ret = futex_lock_pi(uaddr, flags, val, timeout, 0);break;case FUTEX_UNLOCK_PI:if (futex_cmpxchg_enabled)ret = futex_unlock_pi(uaddr, flags);break;case FUTEX_TRYLOCK_PI:if (futex_cmpxchg_enabled)ret = futex_lock_pi(uaddr, flags, 0, timeout, 1);break;case FUTEX_WAIT_REQUEUE_PI:val3 = FUTEX_BITSET_MATCH_ANY;ret = futex_wait_requeue_pi(uaddr, flags, val, timeout, val3, uaddr2);break;case FUTEX_CMP_REQUEUE_PI:ret = futex_requeue(uaddr, flags, uaddr2, val, val2, &val3, 1);break;default:ret = -ENOSYS;}return ret;}
使用strace捕获系统调用时的一些参数如下:
futex(0x7fbf0e41e0ac, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x7fbf0e41e0a8, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1} <unfinished ...>
12312 write(8, "\1\0\0\0\0\0\0\0", 8 <unfinished ...>
12324 <... futex resumed> ) = 0
12307 <... futex resumed> ) = 1
12312 <... write resumed> ) = 8
12324 futex(0x7fbf0e41e080, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
12312 futex(0x7fbf1a41e0ac, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
12307 futex(0x7fbf0e41e080, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
12324 <... futex resumed> ) = -1 EAGAIN (Resource temporarily unavailable)
12307 <... futex resumed> ) = 0
12324 futex(0x7fbf0e41e080, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
12307 futex(0x7fbf1341e16c, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x7fbf1341e168, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1} <unfinished ...>
12324 <... futex resumed> ) = 0
12319 <... futex resumed> ) = 0
12307 <... futex resumed> ) = 1
12324 write(8, "\1\0\0\0\0\0\0\0", 8 <unfinished ...>
12319 futex(0x7fbf1341e140, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
12307 futex(0x7fbf1341e140, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
12324 <... write resumed> ) = 8
12319 <... futex resumed> ) = -1 EAGAIN (Resource temporarily unavailable)
12307 <... futex resumed> ) = 0
12324 futex(0x7fbf0e41e0ac, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
12319 futex(0x7fbf1341e140, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
12307 futex(0x7fbf1e42128c, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x7fbf1e421288, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1} <unfinished ...>
12319 <... futex resumed> ) = 0
12308 <... futex resumed> ) = 0
12307 <... futex resumed> ) = 1
12319 write(8, "\1\0\0\0\0\0\0\0", 8 <unfinished ...>
12308 futex(0x7fbf1e421260, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
12307 futex(0x7fbf1e421260, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
grep其中一个线程的
12324 futex(0x7fbf0e41e080, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
12324 <... futex resumed> ) = 0
12324 write(8, "\1\0\0\0\0\0\0\0", 8 <unfinished ...>
12324 <... write resumed> ) = 8
12324 futex(0x7fbf0e41e0ac, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
12324 <... futex resumed> ) = 0
12324 futex(0x7fbf0e41e080, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
12324 <... futex resumed> ) = -1 EAGAIN (Resource temporarily unavailable)
12324 futex(0x7fbf0e41e080, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
12324 <... futex resumed> ) = 0
12324 write(8, "\1\0\0\0\0\0\0\0", 8) = 8
12324 futex(0x7fbf0e41e0ac, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
12324 <... futex resumed> ) = 0
12324 futex(0x7fbf0e41e080, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
12324 <... futex resumed> ) = -1 EAGAIN (Resource temporarily unavailable)
12324 futex(0x7fbf0e41e080, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
12324 <... futex resumed> ) = 0
12324 write(8, "\1\0\0\0\0\0\0\0", 8 <unfinished ...>
12324 <... write resumed> ) = 8
12324 futex(0x7fbf0e41e0ac, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...>
12324 <... futex resumed> ) = 0
其中futex的第三个参数是futex的具体cmd,定义如下:
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
#define FUTEX_FD 2
- spinlock与mutex对比
- mutex与spinlock
- Spinlock 与mutex 的区别
- mutex spinlock
- 内核同步措施(spinlock与mutex)
- spinlock,mutex,semaphore,vitical section的作用与区别?
- spinlock,mutex,semaphore,vitical section的作用与区别
- spinlock,mutex,semaphore,critical section的作用与区别
- spinlock,mutex,semaphore,critical section的作用与区别
- Linux并发与同步(一)原子操作/spinlock/mutex
- Linux: spinlock and mutex
- spinlock mutex semaphore rwlock
- Processing , Mutex and SpinLock
- mutex, spinlock, semaphore
- mutex 和 spinlock 对比
- spinlock, semaphore 和 mutex
- pthread mutex vs spinlock
- spinlock vs. mutex
- MFC技术内幕系列之(二)---MFC文档视图结构内幕
- Quick小白书系列(四)Quick中的Scene
- HDU 1016 Prime Ring Problem
- 悟空学Linux专栏----第28篇
- 在pu项目(第一个项目)中目前所学到的小知识
- mutex与spinlock
- 如何使用命令 将文件夹打成jar包
- SQLite3
- Quick小白书系列(五)Quick中的Sprite之动起来
- 悟空学Linux专栏----第29篇
- tomcat 性能优化(根据自己实际情况配置)
- 关于H.264中句法元素的一些总结
- 转载:为什么你应该(从现在开始就)写博客
- [Exercise 2] 多元线性回归