glibc互斥锁、自旋锁、信号量、once、sleep实现原理
glibc pthread_mutex_t实现原理
__pthread_mutex_lock
-> lll_lock: 宏, 传递指针给__lll_lock宏
-> __lll_lock: cas替换pthread_lock_t->__data.__lock 0->1成功则返回, 失败根据是否锁为私有走下面的方法
-> __lll_lock_wait / __lll_lock_wait_private: futex为2直接lll_futex_wait, 然后死循环cas切换为2, 如果旧值为0, 则返回, 否则调用lll_futex_wait
-> lll_futex_wait: 走futex系统调用
__pthread_mutex_unlock
-> __pthread_mutex_unlock_usercnt
-> lll_unlock
-> __lll_unlock: exchange(test and set)切换pthread_lock_t->__data.__lock为0, 如果旧值为2则调用lll_futex_wake
-> lll_futex_wake: 走futex系统调用
futex是fast userspace mutexes的缩写,用户态和内核态的混合同步机制,提高在低竞争时候的处理效率(减少系统调用)。
glibc pthread_spinlock_t实现原理(volatile int)
pthread_spin_lock: 通过cas设置值为1, 设置失败循环cas设置值为1, 循环期间设置失败执行汇编asm ("rep; nop")
pthread_spin_unlock: 设置值为0, 通过__asm ("" ::: "memory");防止编译乱序。
glibc semaphore实现原理
sem_init:
-> __new_sem_init: 内部将sem_t*转为struct new_sem*处理, 并设置value为isem->data = value。
sem_wait:
-> __new_sem_wait
-> __new_sem_wait_fast: 判断是否data低32位大于>0, 等于0返回-1进入slow path, 否则cas进行-1操作, 成功返回0直接sem_wait成功, 失败返回-1, 进入slow path
-> __new_sem_wait_slow: 对高32位加1(增加waiter), 死循环执行如下流程, 如果低32位为0, 则调用 do_futex_wait 方法, 如果超时或者信号中断返回, 设置errno, 并对高32位-1(减少waiter), 并返回, 否则futex正常返回则重新获取sem->data, 再次判断低32位。如果低32位不为0, 则cas对低32位-1和高32位-1成功则返回。
-> do_futex_wait: 走futex系统调用
sem_post:
-> __new_sem_post: 原子加载sem->data, 死循环执行, 如果低32位溢出, 设置errno位EOVERFLOW, 返回-1, 否则对低32位通过cas进行+1操作, cas成功后退出循环, 并调用futex_wake唤醒等待者。
glibc pthread_once_t实现原理(int值)
__pthread_once: 通过atomic_load_acquire获取值, 如果值为2表示完成, 立即返回
-> __pthread_once_slow: 第一次进入的线程通过cas把值改成1, 然后调用方法, 然后其他线程调用pthread_once时, 如果值为1, 则调用futex_wait_simple进入等待, 当执行方法的线程完成后, 把值改为2, 并调用futex_wake唤醒线程。
-> futex_wake
-> lll_futex_wake: 走futex系统调用
-> futex_wait_simple
-> futex_wait
-> lll_futex_timed_wait: 走futex系统调用
glibc pthread 锁实现原理:
- http://m.blog.chinaunix.net/uid-29680694-id-5768277.html
- http://m.blog.chinaunix.net/uid-29680694-id-5768277.html
Futex实现:https://www.cnblogs.com/bbqzsl/p/6757923.html
glibc sleep实现代码
unsigned int
__sleep (unsigned int seconds)
{
int save_errno = errno;
const unsigned int max
= (unsigned int) (((unsigned long int) (~((time_t) 0))) >> 1);
struct timespec ts = { 0, 0 };
do
{
if (sizeof (ts.tv_sec) <= sizeof (seconds))
{
/* Since SECONDS is unsigned assigning the value to .tv_sec can
overflow it. In this case we have to wait in steps. */
ts.tv_sec += MIN (seconds, max);
seconds -= (unsigned int) ts.tv_sec;
}
else
{
ts.tv_sec = (time_t) seconds;
seconds = 0;
}
if (__nanosleep (&ts, &ts) < 0)
/* We were interrupted.
Return the number of (whole) seconds we have not yet slept. */
return seconds + ts.tv_sec;
}
while (seconds > 0);
__set_errno (save_errno);
return 0;
}
weak_alias (__sleep, sleep)
int
__nanosleep (const struct timespec *requested_time,
struct timespec *remaining)
{
// 系统调用nanosleep
return SYSCALL_CANCEL (nanosleep, requested_time, remaining);
}
sleep会被信号打断,是不精确的,可以使用SIG_ALARM信号或者clock_nanosleep进行高精度定时。

浙公网安备 33010602011771号