手工打造一把锁

简介: 接上篇(https://yq.aliyun.com/articles/59034 ),我们知道了lock的意义。回到之前的多线程加法操作,当然也可以通过pthread提供的互斥锁来保证结果是正确的。那互斥锁本身是如何保证原子性的呢?当然首先获得锁的操作需要是一个指令,而不能用加载-比对-存储这种类.

接上篇(https://yq.aliyun.com/articles/59034 ),我们知道了lock的意义。回到之前的多线程加法操作,你也可以通过pthread提供的互斥锁来保证结果是正确的。但互斥锁本身是如何保证原子性的呢?当然首先获得锁的操作需要是一个指令,而不能用加载-比对-存储这种类似的三条指令;其次,如果是多核系统上,这个指令本身还需要加上lock前缀。x86提供了cmpxchg指令(http://x86.renejeschke.de/html/file_module_x86_id_41.html ),这类指令有个名词,就是CAS(Compare-and-swap, https://en.wikipedia.org/wiki/Compare-and-swap )便是许多锁操作实现的基础。一个最简单的实现方案大概如下(x86-64, gcc):


typedef volatile unsigned long lock_t;

void foobar_lock(lock_t *lock)
{
    unsigned long old   = 0;
    unsigned long new = 1;
    unsigned char result;
    while (1) {
        asm volatile(
            "lock \n"
            "cmpxchgq  %3, %1 \n"
            "sete      %0\n"
            : "=a" (result) : "m" (*lock), "a" (old), "r"(new) : "cc", "memory");
        if (result) {
            return;
        }
        sched_yield();
    }
}

void foobar_unlock(lock_t *lock)
{
    *lock = 0;
}

cmpxchg会比较rax寄存器的内容,和指定内存的内容,如果相等,会设置ZF=1,并将内存的内容改写为指定的其他内容;否则,将设置ZF=0,并将指定内存位置的内容复制到rax寄存器。而这些是在一条指令内完成的。

对于互斥锁的实现而言,初始为0,已锁为1,通过比较锁所在内存和0,相等则将其设置为1,并设置ZF=1,表示加锁成功。然后我们通过sete来获得ZF的值来判断锁的结果,失败则继续尝试。

之所以需要将0和1先存储到unsigned long,而不是"a"(0)这种立即数的形式,因为发现即便在64位平台,对于这种形式,gcc分配的寄存器是eax,而不是rax。

然后写一段测试代码,代码和上篇文章类似,结果正常:

images55

如果你把lock前缀去掉,同时通过taskset设置单个核心,那么也没有问题。

但是如果去掉了lock前缀,同时又允许多个核心运行,有可能结果小于正确数字,有可能程序hang住。前者可以理解,由于没有lock前缀,会产生两个线程都认为自己加锁成功了,进而同时进入了临界区;后者的情况相对复杂,通过gdb attach到那个进程去,会发现两个线程内部,看到的锁所在的内存,都是1,然额还不知道这是缓存一致性导致的问题,还是乱序执行导致的问题。

目录
相关文章
|
云安全 安全 网络安全
|
6天前
|
JavaScript 安全 前端开发
Nodejs Brotli decoder 代码执行漏洞 (CVE-2026-111497)10629
Node.js发布安全更新修复Brotli解码器高危RCE漏洞(CVE-2026-111497),建议受影响版本用户立即升级。
1969 1
|
12天前
|
人工智能 API 开发工具
DeepSeek Harness 神插件:白嫖 13 家大厂模型
`dsh-our-free-model` 是 DeepSeek Harness 神级插件:零配置、零API Key、零账号,聚合13家大厂免费模型(含DeepSeek V4.1 Flash、Kimi K3等),支持本地网关、用量看板与自动降级,真正实现“白嫖即用”。
2039 40
|
9天前
|
Web App开发 人工智能 前端开发
2026 年 AI 浏览器怎么选?Ego Lite、Tabbit、Chrome DevTools MCP 深度对比,开发者到底该用哪个?
2026年AI浏览器选型指南:Ego Lite专注多Agent协同(Mac优先),Tabbit国产首选,原生支持Windows与Codex控制;Chrome DevTools MCP非浏览器而是开发者利器,深度集成Console/Network/Performance调试能力,让AI真正“看懂并验证”前端代码。
1332 3
|
13天前
|
JSON 程序员 数据格式
最新版Notepad++下载、安装、配置保姆级教程(附官网安装包)
Notepad++ 是一款免费开源、轻量快速的 Windows 文本编辑器,支持多标签、语法高亮、代码折叠与宏录制,体积小、启动快、资源占用低,兼容 x64/x32/ARM 架构,是程序员和文字工作者的高效利器。
2495 0
|
6天前
|
安全 应用服务中间件 Go
PHP2Shell 漏洞拆解:WordPress 与 nginx 为何中招
PHP2Shell 双 RCE 已遭在野利用:WordPress、Drupal 全在射程内,nginx 其实另有洞。拆成因与修复顺序
PHP2Shell 漏洞拆解:WordPress 与 nginx 为何中招
|
13天前
|
安全 Linux 芯片
【万字长文】Ollama下载、安装、配置、使用保姆级教程(2026最新图解)
Ollama 是一款免费开源的本地大模型运行工具,支持 DeepSeek、Qwen 等主流模型,一条命令即可下载运行。2026 最新版 v0.35.1 官方安装包(1.47GB)已提供国内直连下载,纯本地、离线可用、无广告、无隐私泄露风险。
1251 5
|
6天前
|
开发者 索引
DeepSeekHarness大肥鱼自带插件市场了?加个地址就能用
Open Plugin Market 是一个开放插件索引平台,收录800+优质DSH插件,支持分类浏览、智能推荐与随机发现。无需安装市场,粘贴索引地址即可一键接入,网页版直访 dshopen.org,助力小开发者被看见。(239字)
1371 1
DeepSeekHarness大肥鱼自带插件市场了?加个地址就能用
|
5天前
|
安全 程序员 应用服务中间件
PHP 被曝两大致命漏洞,请所有程序员抓紧做这件事!
PHP 官方发布了紧急安全更新,一口气修复了两个严重漏洞。如果网站和服务器用了 PHP 应该怎么处理?漏洞的原理是什么?本文给你讲清楚
618 0

热门文章

最新文章