当前位置: 首页 > news >正文

linux mutex

常规的理解,mutex,就是获取锁,没获取到就挂起。其实 read the fxxk source code之后,发现了其实内里还有很多细节,针对一些场景做优化。

总结起来,就是尽量站住cpu,不休眠下去,等别人释放锁的第一时间就接住。

先上数据结构:

struct mutex {atomic_long_t		owner;raw_spinlock_t		wait_lock;
#ifdef CONFIG_MUTEX_SPIN_ON_OWNERstruct optimistic_spin_queue osq; /* Spinner MCS lock */
#endifstruct list_head	wait_list;
#ifdef CONFIG_DEBUG_MUTEXESvoid			*magic;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lockdep_map	dep_map;
#endif
};

owner 原子结构,用法for() {cmpxchg},看似是一个变量,实则内里乾坤。owner分为两部分,高位部分是持有锁的task_struct指针,由于其字节对齐,低位没用,所以这里被抠出来三个bit。

 * @owner: contains: 'struct task_struct *' to the current lock owner,* NULL means not owned. Since task_struct pointers are aligned at* at least L1_CACHE_BYTES, we have low bits to store extra state.* Bit0 indicates a non-empty waiter list; unlock must issue a wakeup.* Bit1 indicates unlock needs to hand the lock to the top-waiter* Bit2 indicates handoff has been done and we're waiting for pickup.*/
#define MUTEX_FLAG_WAITERS	0x01
#define MUTEX_FLAG_HANDOFF	0x02
#define MUTEX_FLAG_PICKUP	0x04

要是光看这个注释,给你看蒙蔽。

bit0 是一个状态位,置位代表现在这个锁有人在等,也就是wait_list上挂着waiter。

bit1 和 bit2 其实是用来握手的通讯位。比如A持有锁,B等着锁,且B是wait_list最top的waiter,则B置位bit1 handoff,然后A释放锁的时候,发现handoff置位,则把owner设置成top waiter,并且把 bit 2置位pickup,bit1清掉。实现一个简单握手。当B检查到pickup位,且owner与自己current相等,则自己获取到锁咯。

这里引出一个逻辑,除了锁没人等,则owner是由持有锁的线程释放锁的时候,将owner设置成top waiter的task_struct, 而不是由申请锁的线程来修改owner。击鼓传花。

然后就是链表wait_list,用来放置waiter,既然是链表,就少不了wait_lock锁来锁住.wait_list上挂的数据结构如下,没啥好说的:

struct mutex_waiter {struct list_head	list;struct task_struct	*task;struct ww_acquire_ctx	*ww_ctx;
#ifdef CONFIG_DEBUG_MUTEXESvoid			*magic;
#endif
};

几个关键函数注解:

static inline struct task_struct *__mutex_trylock_common(struct mutex *lock, bool handoff)
{unsigned long owner, curr = (unsigned long)current;owner = atomic_long_read(&lock->owner);for (;;) { /* must loop, can race against a flag */// 从owner变量内 提取那三个bit flagunsigned long flags = __owner_flags(owner);// 从owner变量内 提取当前持有者的 task_structunsigned long task = owner & ~MUTEX_FLAGS;if (task) {// 如果当前有人持有锁if (flags & MUTEX_FLAG_PICKUP) {//如果pick_up置位,则持有者释放锁,并交权咯if (task != curr)//如果当前 task_struct 与本线程的不相等,则现在这个锁不是给我的break;flags &= ~MUTEX_FLAG_PICKUP;// 走到这里说明这个锁现在是给我的,把pickup清掉 } else if (handoff) { //如果 handoff 传参为1,则置位 handoff 位//这里再说一下,只有当前task是wait_list的第一个,handoff才是1if (flags & MUTEX_FLAG_HANDOFF)//已经置位了,不用管了break;flags |= MUTEX_FLAG_HANDOFF;// 没有置位,置位} else {break;//啥都没有,还是走吧}} else { //如果当前没人持有锁,就是没锁//这里告警,flag有置位,但是还走到这里了,不应该啊,有bugMUTEX_WARN_ON(flags & (MUTEX_FLAG_HANDOFF | MUTEX_FLAG_PICKUP));task = curr;//直接把 task设置成本大爷的。}// 原子操作cmpxchg,可能会失败,所以要for(;;)if (atomic_long_try_cmpxchg_acquire(&lock->owner, &owner, task | flags)) {if (task == curr)//如果 task是自己,则获取成功咯,直接return NULLreturn NULL;break;}}//跟我没关系,return 现在的taskreturn __owner_task(owner);
}
__mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,struct list_head *list)
{hung_task_set_blocker(lock, BLOCKER_TYPE_MUTEX);debug_mutex_add_waiter(lock, waiter, current);//无脑往队列tail一塞,如果是第一个则,置位waiter flaglist_add_tail(&waiter->list, list);if (__mutex_waiter_is_first(lock, waiter))__mutex_set_flag(lock, MUTEX_FLAG_WAITERS);
}
static noinline
bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner,struct ww_acquire_ctx *ww_ctx, struct mutex_waiter *waiter)
{bool ret = true;lockdep_assert_preemption_disabled();while (__mutex_owner(lock) == owner) {//保证这个锁控制权一直在这一个家伙手里/** Ensure we emit the owner->on_cpu, dereference _after_* checking lock->owner still matches owner. And we already* disabled preemption which is equal to the RCU read-side* crital section in optimistic spinning code. Thus the* task_strcut structure won't go away during the spinning* period*/barrier();/** Use vcpu_is_preempted to detect lock holder preemption issue.*///这个注释还是老版本的注释,代码已经更新了,差评啊差评//这里判断锁的持有者 是否还在cpu上面跑,如果不在cpu上面跑了,//也没必要等下去了,应为他也释放不了锁了//然后判断本cpu有人没有线程要跑,如果有其他线程想跑,咱先让一让。if (!owner_on_cpu(owner) || need_resched()) {ret = false;break;}if (ww_ctx && !ww_mutex_spin_on_owner(lock, ww_ctx, waiter)) {ret = false;break;}cpu_relax();}return ret;
}

http://www.dtcms.com/a/474710.html

相关文章:

  • 河南中原建设公司网站wordpress代码实现
  • 什么网站动物和人做的网络设计中网络设备选择的原则
  • 做设计接外快在哪个网站成都注册公司的流程及手续
  • WPF中核心接口 INotifyPropertyChanged​
  • 【完整源码+数据集+部署教程】 面包种类识别系统源码和数据集:改进yolo11-aux
  • qData数据中台商业版实操全流程演示(2025年10月版)
  • 南昌网站建设公司价位广州市门户网站建设
  • 机器视觉3D定位引导成功的一半机械臂TCP工具,什么是机械臂TCP工具?为什么TCP如此重要?如何定义和设置TCP?
  • 自动化测试,预制菜和大厨现制
  • 计算机本科论文 网站建设东莞网站关键词优化怎么做
  • Linux 通配符与正则表达式(含实战案例+避坑指南)
  • GO语言篇之Slice
  • 长春建站培训班广告设计制作公司简介
  • git简介,版本控制系统,储存方式
  • 南京制作网站建站模板公司网站建设工资怎么样
  • .net 6 signalr
  • 从零到一:基于.NET 9.0构建企业级AI智能体对话平台的实战之旅
  • 网站建设费用标准wordpress 只剩纯文本
  • mysql基础【函数 与 约束】
  • 昆明免费建站模板玉石网站建设的定位
  • 什么视频网站可以做链接地址新闻发稿114
  • 重庆网站建设模板制作蒙自做网站的公司
  • 什么是web前端?
  • Win10,在ESP分区添加PE系统,隐藏VTOYEFI分区
  • Qwen3(通义千问3)、OpenAI GPT-5、DeepSeek 3.2、豆包最新模型(Doubao 4.0)通用模型能力对比
  • 小学做试卷的网站wordpress跳转页面
  • 外国设计网站推荐网页制作作业下载
  • JavaScript入门分享_JavaScript日常处理
  • layui 企业网站模板域名注册服务商网站
  • Linux 文件描述符详解