x86指令集中lock前缀的意义

接上篇(https://yq.aliyun.com/articles/59019 ),对一个变量进行加法操作,可以是3条指令,也可以是1条指令。区别在于,1条指令属于原子操作,不会被打断,那是不是只要1条指令的形式,多线程之间就不需要加锁了呢?我们先试试看。(以下代码仅适用于x86平台,gcc编译器)

#include <stdio.h>
#include <pthread.h>

int count = 0;

void *add(void *arg)
{
    int i;

    for (i = 0; i< 10000; i++) {
        asm(
            "addl $1, %0 \n"
            : : "m"(count) : );
    }
}

int main(int argc, char *argv[])
{
    pthread_t t1, t2;

    pthread_create(&t1, NULL, add, NULL);
    pthread_create(&t2, NULL, add, NULL);

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    printf("%d\n", count);
    return 0;
}

然后运行:
x86指令集中lock前缀的意义

这是在一个多核处理器且支持对称多处理的系统上运行的结果。可见很大概率上,仍然存在同步问题。那为什么某些情况又能得到20000这个正确结果呢?鬼才知道,只能靠瞎猜。

多核多线程情况下,即便修改操作是单条指令,由于存在并发运行,也不能保证其原子性。幸好有taskset这个程序,可以设置cpu亲和性,我们先将其设置到单核试试看。

x86指令集中lock前缀的意义

嗯貌似完美。

那如果亲和性设置成两个核心呢?

x86指令集中lock前缀的意义

果然,有一定概率出现同步问题。

好了,文章要结束了,总得回到标题,类似电影要到时间了,反派再强大,也得找个方式被灭掉。lock前缀的意义在于,在多核且支持对称多处理的系统上,对于接下来的那条指令,能够保证其原子性。注意lock并不是能够往各个指令面前加的。至于如何保证了原子性,鬼才知道。

我们把add函数改写下:

  for (i = 0; i< 10000; i++) {
        asm(
            "lock \n"
            "addl $1, %0 \n"
            : : "m"(count) : );
    }

再运行几遍:

x86指令集中lock前缀的意义

好了,像是那么回事了。

上一篇:一些有用的javascript实例分析(三)


下一篇:动手为王 | Oracle 数据库跨版本升级迁移实践