首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CPU指令重排序

CPU指令重排序
EN

Stack Overflow用户
提问于 2014-04-06 16:10:13
回答 2查看 795关注 0票数 0

我们的处理器可以重新排序指令,以获得一些性能上的好处,但这可能会导致一些奇怪的行为。我试图在这篇文章的基础上重现其中的一个问题。

这是我的密码:

代码语言:javascript
复制
int a,b;
int r1,r2;
mutex m1,m2;

void th1()
{
    for(;;)
    {
        m1.lock();
        a=1;
        asm volatile("" ::: "memory"); 
        r1=b;
        m1.unlock();
    }
}

void th2()
{
    for(;;)
    {
        m2.lock();
        b=1;
        asm volatile("" ::: "memory"); 
        r2=a;
        m2.unlock();
    }
}

int main()
{
    int cnt{0};
    thread thread1{th1};
    thread thread2{th2};
    thread1.detach();
    thread2.detach();
    for(int i=0;i<10000;i++)
    {
        m1.lock();
        m2.lock();
        a=b=0;
        m1.unlock();
        m2.unlock();
        if(r1==0&&r2==0)
        {
            ++cnt;
        }
    }
    cout<<cnt<<" CPU reorders happened!\n";
}

我使用互斥来确保“主”线程在th1或th2执行它们的任务时不会修改a或b,执行的输出一直在变化,可能是0,可能是10000,或者是0到10000之间的偶然数字。

这段代码有些地方让我有点不适应,我不确定它是否真的再现了CPU重新排序的现象。

从代码看,r1和r2在'if‘中可能是0的唯一方式是因为th1和th2将它们设置为'a’和'b‘的值,而在th1和th2的上下文中,由于锁机制的原因,这个值不能是0,而这些变量是0的唯一方式是因为指令重新排序,这是正确的吗?

谢谢

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-04-06 19:16:26

您的程序与您从preshing.com引用的文章中的程序非常不同。preshing.com程序使用信号量,而您的程序使用互斥量。

穆特克斯比信号更简单。他们只能保证一次只有一个线程可以锁定互斥对象。也就是说,它们只能用于互斥。

preshing.com程序用它的信号量做了一些您无法单独使用互斥的事情:它同步三个线程中的循环,以便它们都按锁定步骤进行。Thread1和Thread2分别在其循环的顶部等待,直到main()释放它们,然后main在其循环的底部等待,直到它们完成工作。然后他们都再转一圈。

你不能用互斥来做这件事。在您的程序中,在其他两个线程运行之前阻止main循环数千次的原因是什么?无非是偶然。也没有什么可以阻止Thread1和/或Thread2在main()被阻塞时循环数千次,等待下一个时间切片。

记住,信号量就是计数器。仔细查看preshing.com中的信号量是如何由线程递增和减少的,您将看到它如何保持线程同步。

票数 1
EN

Stack Overflow用户

发布于 2014-04-07 05:51:58

我犯了一个错误,使用互斥而不是信号量(谢谢james ),这是正确工作的代码:

代码语言:javascript
复制
#include <mutex>
#include <condition_variable>
using namespace std;

class semaphore{
private:
    mutex mtx;
    condition_variable cv;
    int cnt;

public:
    semaphore(int count = 0):cnt(count){}
    void notify()
    {
        unique_lock<mutex> lck(mtx);
        ++cnt;
        cv.notify_one();
    }
    void wait()
    {
        unique_lock<mutex> lck(mtx);

        while(cnt == 0){
            cv.wait(lck);
        }
        --cnt;
    }
};

int a,b;
int r1,r2;
semaphore s1,s2,s3;

void th1()
{
    for(;;)
    {
        s1.wait();
        a=1;
        asm volatile("" ::: "memory");
        r1=b;
        s3.notify();
    }
}

void th2()
{
    for(;;)
    {
        s2.wait();
        b=1;
        asm volatile("" ::: "memory");
        r2=a;
        s3.notify();
    }
}

int main()
{
    int cnt{0};
    thread thread1{th1};
    thread thread2{th2};
    thread1.detach();
    thread2.detach();
    for(int i=0;i<100000;i++)
    {
        a=b=0;
        s1.notify();
        s2.notify();
        s3.wait();
        s3.wait();

        if(r1==0&&r2==0)
        {
            ++cnt;
        }
    }
    cout<<cnt<<" CPU reorders happened!\n";
}

重新排序似乎被适当地复制了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22896524

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档