一个关于Memory Reordering的实验

原创 2013年09月16日 22:08:52

  Instruction Reordering有两种,包括Compiler Reordering和Memory Reordering。


  Intel官方列出的有关Memory Reordering的情况总共有8种:

  Neither Loads Nor Stores Are Reordered with Like Operations

  Stores Are Not Reordered With Earlier Loads

  Loads May Be Reordered with Earlier Stores to Different Locations

  Intra-Processor Forwarding Is Allowed

  Stores Are Transitively Visible

  Stores Are Seen in a Consistent Order by Other Processors

  Locked Instructions Have a Total Order

  Loads and Stores Are Not Reordered with Locked Instructions

  

  可以看出,第三点是会发生指令重排的情况。




  下面做一个验证第三点的实验,参考《Memory Reordering Caught in the Act》一文,

  原文链接:http://preshing.com/20120515/memory-reordering-caught-in-the-act

  (注:原文采用的是windows平台,这里采用linux平台)


  

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>

sem_t beginSema1;
sem_t beginSema2;
sem_t endSema;

int X,Y;
int r1,r2;

void* thread1Func(void* param) {
	while (1) {
		sem_wait(&beginSema1);
		while ( (rand() / (double)RAND_MAX) > 0.2 ) ;
		X=1;
		__asm__ __volatile__("":::"memory");
		r1 = Y;
		sem_post(&endSema);
	}
	return NULL;
}

void* thread2Func(void* param) {
	while (1) {
		sem_wait(&beginSema2);
		while ( (rand() / (double)RAND_MAX) > 0.2 ) ;
		Y=1;
		__asm__ __volatile__("":::"memory");
		r2 = X;
		sem_post(&endSema);
	}
	return NULL;
}


int main() {
	sem_init(&beginSema1,0,0);
	sem_init(&beginSema2,0,0);
	sem_init(&endSema,0,0);

	pthread_t thread1,thread2;

	pthread_create(&thread1,NULL,thread1Func,NULL);
	pthread_create(&thread2,NULL,thread2Func,NULL);

	int detected = 0;
	int iterations = 0;
	for (iterations=1;;iterations++) {
		X=0;
		Y=0;
		sem_post(&beginSema1);
		sem_post(&beginSema2);
		sem_wait(&endSema);
		sem_wait(&endSema);
		if (r1 == 0 && r2 == 0) {
			detected++;
			printf("%d reorders detected after %d iterations\n", detected, iterations);
		}
	}
	return 0;
}

  

  其中,__asm__ __volatile__("":::"memory") 是禁止编译器进行指令重排,保证了store操作和load操作在编译后的先后顺序。

  可以发现,输出结果出现了 r1==0&&r2==0 的情况,证明CPU对指令进行了重排。





  下面,再将__asm__ __volatile__("":::"memory") 改为 __asm__ __volatile__("mfence":::"memory"),强制使用strong ordering的模式,保证CPU不对该句前后的store和load操作进行重排:

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>

sem_t beginSema1;
sem_t beginSema2;
sem_t endSema;

int X,Y;
int r1,r2;

void* thread1Func(void* param) {
	while (1) {
		sem_wait(&beginSema1);
		while ( (rand() / (double)RAND_MAX) > 0.2 ) ;
		X=1;
		__asm__ __volatile__("mfence":::"memory");
		r1 = Y;
		sem_post(&endSema);
	}
	return NULL;
}

void* thread2Func(void* param) {
	while (1) {
		sem_wait(&beginSema2);
		while ( (rand() / (double)RAND_MAX) > 0.2 ) ;
		Y=1;
		__asm__ __volatile__("mfence":::"memory");
		r2 = X;
		sem_post(&endSema);
	}
	return NULL;
}


int main() {
	sem_init(&beginSema1,0,0);
	sem_init(&beginSema2,0,0);
	sem_init(&endSema,0,0);

	pthread_t thread1,thread2;

	pthread_create(&thread1,NULL,thread1Func,NULL);
	pthread_create(&thread2,NULL,thread2Func,NULL);

	int detected = 0;
	int iterations = 0;
	for (iterations=1;;iterations++) {
		X=0;
		Y=0;
		sem_post(&beginSema1);
		sem_post(&beginSema2);
		sem_wait(&endSema);
		sem_wait(&endSema);
		if (r1 == 0 && r2 == 0) {
			detected++;
			printf("%d reorders detected after %d iterations\n", detected, iterations);
		}
	}
	return 0;
}


  可以发现,输出结果中没有了 r1==0&&r2==0 的情况。


c++11的std::memory_order

首先明确一点,std::atmoic和std::memory_order只有在多cpu多线程情况下,无锁编程才会用到。在x86下,由于是strong memory order的,所以很多时候只需要考虑...
  • chenxinl
  • chenxinl
  • 2012-08-21 11:22:37
  • 2837

C++11 并发指南七(C++11 内存模型一:介绍)

第六章主要介绍了 C++11 中的原子类型及其相关的API,原子类型的大多数 API 都需要程序员提供一个 std::memory_order(可译为内存序,访存顺序) 的枚举类型值作为参数,比如:a...
  • tanningzhong
  • tanningzhong
  • 2017-09-26 14:21:48
  • 64

Memory Reordering Caught in Act

前言: 首先是翻译的几篇文章,作者是一个老外,虽然文章是几年前的,但是很值得一读。 最近不知道写些什么东西,拿这个先凑几篇其次有关什么memory ordering,memory reorderi...
  • sparkliang
  • sparkliang
  • 2016-10-19 15:13:17
  • 1144

浅谈Memory Reordering

原文:http://dreamrunner.org/blog/2014/06/28/qian-tan-memory-reordering/   Memory ordering 在我们...
  • hintonic
  • hintonic
  • 2017-12-11 11:06:22
  • 121

HDU 5500 Reorder the Books(贪心+思维)

Description dxy家收藏了一套书,这套书叫《SDOI故事集》,《SDOI故事集》有n(n≤19)n(n\leq 19)n(n≤19)本,每本书有一个编...
  • qq_34374664
  • qq_34374664
  • 2016-11-28 13:40:53
  • 613

String reorder

Time Limit: 10000ms Case Time Limit: 1000ms Memory Limit: 256MB Description For ...
  • shuilansedeyuer
  • shuilansedeyuer
  • 2014-04-15 18:37:11
  • 208

Memory reordering

Memory Barriers and JVM Concurrency  对主存的一次访问一般花费硬件的数百次时钟周期。处理器通过缓存(caching)能够从数量级上降低内存延迟的成本这些缓存为...
  • dannyPolyu
  • dannyPolyu
  • 2013-03-26 19:46:30
  • 399

Reorder array

Given a descending array A, reorder it to: Ln→L0→Ln-1→L1→Ln-2→L2→…e.g. A = [7, 6, 5, 4, 3, 2, 1] → A...
  • dongyu_1989
  • dongyu_1989
  • 2018-03-07 08:35:15
  • 18

简单说一下C++11的并发

C++11中定义的data race是“不同线程中的两个互相冲突的动作,其中至少有一个不是atomic的,而且无一个动作发生在另一个动作之前”。data race总会导致不可预期的行为。在C++11以...
  • charles_r_chiu
  • charles_r_chiu
  • 2018-04-17 15:16:21
  • 15
收藏助手
不良信息举报
您举报文章:一个关于Memory Reordering的实验
举报原因:
原因补充:

(最多只允许输入30个字)