随想录(再论内存屏障)


【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】


    关于内存屏障,我曾经写过一篇文章,也就是。今天,我自己又发现了关于一篇内存屏障的好文章,也就是。在这篇文章中,我发现它设计的例子特别好,但是存在部分错误,而且也没有windows的版本,所以我打算移植一下。


    晚上,利用跑步后的这一段时间把代码整理了一下,终于可以运行了。关于内存屏障,本质上其实就是多核cpu的cache同步。如果有不清楚的同学,可以参考这篇文章,即, 题目为Memory Barriers: a Hardware View for Software Hackers。


    闲话不多说,先给大家看一下代码。


/*
* file: test memory barrier
* compiler : vs2010 and above
*/

#include <windows.h>
#include <stdio.h>
#include <assert.h>

typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;

BOOL state[2];
u8 turn;
static u32 count = 0;
u32 val = 1000000;

//#define MEM_BARRIER() do {__asm {mfence}}while(0)
#define MEM_BARRIER()


DWORD WINAPI ThreadProc(LPVOID* args)
{
	u8 flag = (u8) args;
	u32 num = 0;
	
	while(num++ < val) {
	
		state[flag] = TRUE;
		turn = 1 - flag;
		MEM_BARRIER();

		while((turn  == (1 - flag)) && state[1 - flag]);
		count++;
		state[flag] = FALSE;
	}

	return 0;
}

int main(int argc, char* argv[])
{
	HANDLE hThread[2];

	while(1) {

		count = 0; turn  =  0; state[1] = state[0] = FALSE;
		hThread[0] = CreateThread(NULL, 0, ThreadProc, 0, CREATE_SUSPENDED, NULL);
		SetThreadAffinityMask( hThread[0], 0x01 );

		hThread[1] = CreateThread(NULL, 0, ThreadProc, 1, CREATE_SUSPENDED, NULL);
		SetThreadAffinityMask( hThread[1], 0x02 );
	
		ResumeThread(hThread[0]);
		ResumeThread(hThread[1]);
		WaitForMultipleObjects(2, hThread, TRUE, INFINITE);

		if(count != 2000000) {
			__asm {int 3}
		}
	}

	return 1;
}


    整个代码最精彩的地方就是利用Peterson算法实现thread之间的互斥。本来对于单core的thread来说,这是没有问题的。但是关键在于当前一个thread运行在core0,另外一个运行在core1之上。这就很可能造成共享变量count是不同步的(cache级别的不同步)。如果大家不使用mfence指令的话,就会发现某些情况下count不是2000000,此时系统就会触发中断。同样,一旦大家使用了这个神奇的指令,之前出现的问题就不复存在了。memory barrier的范例本来就不多,这个算得上是目前为止我所知道的最棒的范例。


    注: 此处的mfence也可以修改为cpuid,cpuid也有mfence的功能。所以如果修改成cpuid之后,就可以在vc6上运行了。


    代码需要在vs2010版本之上运行。欢迎大家一试究竟。体会一下神奇的memory barrier。最后附上linux下的内存屏障代码,编译方法为g++ test.cpp -lpthread,输入./a.out即可。

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

#define mb() asm volatile ("mfence\n\t":::"memory")
int counter = 0;
 
class Peterson
{
public:
  Peterson() {
    turn = 0;
    state[0] = false;
    state[1] = false;
  }

  void lock(int threadID) {
    int self = threadID;
    int oppo = 1 - self;

    state[self] = true;
    turn = oppo;
//    mb();
    while (state[oppo] && turn == oppo) ;
  }

  void unlock(int threadID) {
    int me = threadID;
    state[me] = false;
  }
 
private:
  bool state[2];
  int turn;
};
 
Peterson mtx;

void*
thread(void *arg)
{
  int threadID = (int)arg;
  int i = 0;
  while (i++ < 1000000) {
    mtx.lock(threadID);
    ++counter;
    mtx.unlock(threadID);
  }
}
 
int
main()
{
  pthread_t t1, t2;
  pthread_create(&t1, NULL, thread, (void*)0);
  pthread_create(&t2, NULL, thread, (void*)1);
  pthread_join(t1, NULL);
  pthread_join(t2, NULL);
  fprintf(stderr, "counter: %d\n", counter);
  return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式-老费

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值