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 锁实现原理:

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进行高精度定时。

参考:https://my.oschina.net/emacs_8844266/blog/17403879

posted @ 2025-05-10 17:38  yghr  阅读(47)  评论(0)    收藏  举报