内存一致模型——顺序一致模型

内存一致模型——顺序一致模型

顺序一致模型,是最常见的内存一致模型,定义如下:

【如果一个多处理器系统是顺序一致的】,那么,无论程序怎么运行,结果都与各处理器各自轮流运行后的结果相同,且各处理器内部的执行顺序由程序决定。

从定义中, 可以得出,顺序一致模型有如下要求:

 - 保证单一处理器内部的执行顺序
 - 保证多处理器操作同一块内存时的先后顺序

如图所示:

内存一致模型——顺序一致模型_第1张图片

总线结构保证在相同时间内对指定内存块的访问只有一个处理器。这样就保证多处理器之间不会冲突。

下面展示引用文献[1]中的两个例子(a) (b):

内存一致模型——顺序一致模型_第2张图片

(a)中就用到了Dekker算法,过程一目了然,放一段代码吧

#include 

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\n");
    }
    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\n");
    }
    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的情况出现。在这种情形下就会出现这种冲突,如图所示:

内存一致模型——顺序一致模型_第3张图片

单个核心在读取某内存时,会先检查自己写入缓冲区中是否包含对应地址的内存写入,如果存在则返回写入的值,如上文所提,单核心系统不会存在冲突问题;而如果不存在,则会直接到内存中读取数据。如果有多个核心,图中所示就是引起冲突的原因。

引用:

[1] Sarita V. Adve, Kourosh Gharachorloo.Shared Memory Consistency Models:A Tutorial[R].Palo Alto, California 94301 USA:WRL,1995.

你可能感兴趣的:(多线程)