我们的处理器可以重新排序指令,以获得一些性能上的好处,但这可能会导致一些奇怪的行为。我试图在这篇文章的基础上重现其中的一个问题。
这是我的密码:
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的唯一方式是因为指令重新排序,这是正确的吗?
谢谢
发布于 2014-04-06 19:16:26
您的程序与您从preshing.com引用的文章中的程序非常不同。preshing.com程序使用信号量,而您的程序使用互斥量。
穆特克斯比信号更简单。他们只能保证一次只有一个线程可以锁定互斥对象。也就是说,它们只能用于互斥。
preshing.com程序用它的信号量做了一些您无法单独使用互斥的事情:它同步三个线程中的循环,以便它们都按锁定步骤进行。Thread1和Thread2分别在其循环的顶部等待,直到main()释放它们,然后main在其循环的底部等待,直到它们完成工作。然后他们都再转一圈。
你不能用互斥来做这件事。在您的程序中,在其他两个线程运行之前阻止main循环数千次的原因是什么?无非是偶然。也没有什么可以阻止Thread1和/或Thread2在main()被阻塞时循环数千次,等待下一个时间切片。
记住,信号量就是计数器。仔细查看preshing.com中的信号量是如何由线程递增和减少的,您将看到它如何保持线程同步。
发布于 2014-04-07 05:51:58
我犯了一个错误,使用互斥而不是信号量(谢谢james ),这是正确工作的代码:
#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";
}重新排序似乎被适当地复制了。
https://stackoverflow.com/questions/22896524
复制相似问题