内存一致模型——顺序一致模型
顺序一致模型,是最常见的内存一致模型,定义如下:
【如果一个多处理器系统是顺序一致的】,那么,无论程序怎么运行,结果都与各处理器各自轮流运行后的结果相同,且各处理器内部的执行顺序由程序决定。
从定义中, 可以得出,顺序一致模型有如下要求:
- 保证单一处理器内部的执行顺序
- 保证多处理器操作同一块内存时的先后顺序
如图所示:
![顺序一致性图示](data/attach/1904/62d8hchnddiiz4jv8dh2rjhu8hdvyydq.jpg)
总线结构保证在相同时间内对指定内存块的访问只有一个处理器。这样就保证多处理器之间不会冲突。
下面展示引用文献[1]中的两个例子(a) (b):
![这里写图片描述](data/attach/1904/0kd7yb2dp601xmjqipwouhwti8p0plut.jpg)
(a)中就用到了Dekker算法,过程一目了然,放一段代码吧
size_t signal1 = 0;
size_t signal2 = 0;
volatile bool entered1 = false;
volatile bool entered2 = false;
DWORD __stdcall worker1Thread(LPVOID param)
{
for (int i = 1; i < 100000;)
{
//printf("a1 ");
signal1 = 1;
//printf("a2 ");
size_t tsig = signal2;
if (tsig == 0)
{
// printf("a3 ");
entered1 = true;
// printf("a4 ");
// printf("id : %d ", 1);
bool violated = entered2;
if (violated)
printf("worker1 violated");
// printf("a5 ");
entered1 = false;
// printf("a6 ");
//printf("checked : ",)
i++;
}
// printf("a7 ");
signal1 = 0;
// printf("a8
");
}
return ERROR_SUCCESS;
}
DWORD __stdcall worker2Thread(LPVOID param)
{
for (int i = 1; i < 100000;)
{
// printf("b1 ");
signal2 = 1;
// printf("b2 ");
size_t tsig = signal1;
if (tsig == 0)
{
// printf("b3 ");
entered2 = true;
// printf("id : %d ", 2);
// printf("b4 ");
bool violated = entered1;
if (entered1)
printf("worker2 violated");
// printf("b5 ");
entered2 = false;
// printf("b6 ");
i++;
}
// printf("b7 ");
signal2 = 0;
// printf("b8
");
}
return ERROR_SUCCESS;
}
void test24()
{
CloseHandle(CreateThread(NULL, 0, worker1Thread, NULL, NULL, NULL));
CloseHandle(CreateThread(NULL, 0, worker2Thread, NULL, NULL, NULL));
}
为什么有这么多注释?因为如果你运行这段代码你会发现,会以极低的概率报violated。仔细想想,代码好像又没什么问题。
经过再仔细的分析之后发现,如果某线程在将signal置0之后被操作系统剥夺了cpu时间,那么就会导致冲突出现。下面就会分析无缓存及有缓存情形的一致性模型。
无缓存架构
在很多现如今的CPU实现中,都会有写入缓冲区来作为硬件加速的一种手段。也就是说,CPU对内存的操作会先保存在写入缓冲区中,继而写入内存,而这种行为就导致内存操作非原子。对于单处理器系统而言,并不存在这种问题,因为只有一个处理器,所以写入缓冲区也就只有一个。但是对于多处理器系统来说,就另当别论了,因为各个处理器用的并不是同一块定写入缓冲区,so,问题来了。
多核心多写入缓冲区情况
第一种情形,我们来看一下保证内存写入读取顺序的重要性。在Dekker算法中,对于一个顺序一致模型来说,当进行互斥区进入判断时,并不会存在两个信号量都为0的情况出现。在这种情形下就会出现这种冲突,如图所示:
![多核心多写入缓冲区](data/attach/1904/x5edkkyp5m547rcaq9fczbjqb4toyidd.jpg)
单个核心在读取某内存时,会先检查自己写入缓冲区中是否包含对应地址的内存写入,如果存在则返回写入的值,如上文所提,单核心系统不会存在冲突问题;而如果不存在,则会直接到内存中读取数据。如果有多个核心,图中所示就是引起冲突的原因。
引用:
[1] Sarita V. Adve, Kourosh Gharachorloo.Shared Memory Consistency Models:A Tutorial[R].Palo Alto, California 94301 USA:WRL,1995.