有全局变量 int a;
    有两个线程A,B;
    两线程同时运行,其中A不断改变a的值,B不断读取a的值。
    其中不使用同步,B得到的a的值当然是未知数,
  理论上系统会出错吗?

解决方案 »

  1.   

    我也很关注这个问题。
    如果是 四个字节的数据,或者更短的数据,我认为是没问题的。因为数据这么短,
    数据的传递应该就是原子操作了。不过也很不好讲。我也不确定
    ============================================================================
    DocWizard C++ 程序文档生成工具 http://www.betajin.com/alphasun/index.htm
      

  2.   

    从理论上讲,
    你在线程B中所读到的线程A中的数据,
    至少在顺序上不是线程A所处理得到数据的顺序。
    如果采用进程同步机制才能确保数据的一致性。
      

  3.   

    有这样一个问题,由于DWORD这样的数据很小,那么读取的一方,能不能每次都读取到一个完整的DWORD呢?有可能读取到不完整的DWORD码?
      

  4.   


    mov ax,[a]
    mov [g],axmov ax,[g]
    mov [b],ax
      

  5.   

    单CPU的32位Windows系统中不会出现问题。
    但这样做程序的移植性就太差了
      

  6.   

    即便是多CPU,数据总线也不可能同时被两个CPU占用,它们也是通过总线控制器来分配控制权的。
      

  7.   

    CPU体系结构可以保证不会出现半个DWORD的情形。这是通过处理器高速缓存通知来实现的。原理是:如果一个CPU改写了内存(一般在处理器高速缓存中),它会在总线上发一条通知告诉其他CPU,这块内存已经被改写。其他CPU接收到通知之后就将该内存块设定为已改写,下次需要该内存块中数据的时候,就会从数据总线上读而不是从高速缓存中读。
      

  8.   

    是不是可以这么说
    1。如果数据没有超过数据总线宽度,那么对他的读写是原子操作。(姑且这么说,我也不是很肯定)
    2。如果超过宽度,比如 double,那么就不是原子操作。
      

  9.   

    你说的是汇编语言中的DWORD,不是操作系统中的DWORD
      

  10.   

    用事件同步吧,我就是这样的,没有问题!如:
    threadA:
    evtNowDraw = CreateEvent(NULL, FALSE, FALSE, "evtNowDraw");
    void Write()
    {
        desBuf=*srcBuf;
        // 设置画图事件消息
        SetEvent(evtNowDraw);
    }
    BOOL ThreadA::GetEvent()
    {
    if(WaitForSingleObject(evtNowDraw,YourWaitTimeOut)!=WAIT_TIMEOUT)
    {
    this->ResetEventNowDraw();
    return true;
    }
    else 
    {
    return false;
    }}ThreadB:
    void Read()
    {
        if(ThreadA::GetEvent(evtNowDraw))
         {
          buf=desBuf;
         }
    }
      

  11.   

    to  wabc(wabc) : 
    对于32位系统,无论是操作系统还是硬件, DWORD都是 32 位to  ybeetle(小鬼)
    没错,在这种情况下我不想使用 同步对象,也是处于系统资源耗用的问题。另外程序设计也可以简化。
      

  12.   

    ybeetle(小鬼)  你也不用这样顶阿,太难看了
      

  13.   

    to alphapaopao:难道你只允许程序在32位操作系统运行?
      

  14.   

    64位的电脑原子性只会更好。楼主问的可能是程序是否不能在16位操作系统运行。但估计用16位操作系统做多线程只怕是没有吧。况且Windows NT/2000等不能在16位CPU上跑的。
      

  15.   

    没错,64为机器的原子性会更好。对于16位的机器,担心对DWORD进行操作不是原子操作,这是有理由的。
      

  16.   

    可以肯定地说,16位机器对DWORD操作*不是*原子操作。
      

  17.   

    一个例子,在A中读个字节,a++,B需要对a之前的数据处理,一直到a,这样,即使B读的a不正确,但是至少在a之前,因此不会发生错误。这个例子对不对????
      

  18.   

    这这里作了一个程序,一个线程根据正弦函数关系以每秒1000次的速度写一个WORD,而别一个线程画图,画了一个小时,也没有发现在出格的图呀!
    这个能不能说明一个问题?
      

  19.   

    >>书是说,线程的同步只有在都为写时才需要的,当只有一个写
    >>时,就无所谓了!读是一个原语,不会被中断的!我认为不是这样的,因为写不是原语,所以,即便读是原语, read也会得到不完整的数据。
    想想一下write半个数据,read打断了他,虽然read不能被别人打断(姑且这样假设),
    read得到的数据就是半个数据。
      

  20.   

    LONG InterlockedDecrement(
      LONG volatile* lpAddend
    );
    LONG InterlockedIncrement(
      LONG volatile* lpAddend
    );
    这两个函数是原语操作,由操作系统实现,如果写一个DWORD是原语,那也没有必要
    由这两个函数吧?
      

  21.   

    楼上,DWORD在32为机器上,可能是原子操作,在16位机器上理所当然不会是原子操作。
      

  22.   

    一般不会出错,不过可能出现漏读的可能,例如A在一个时间片里连续多次改变该变量。
    不过如果该变量的地址没有对齐,我想有可能出错,因为程序要读取内存两次才能取出该变量的值。
    例如:
    #pragma pack(push, 1)
    struct test
    {
    char ch;
    int  a;
    };test::a的地址没对齐可能出错。
      

  23.   

    #pragma pack(push, 1)
    struct test
    {
    char ch;
    int  a;
    };
    test::a的地址应该是对齐的
      

  24.   

    可以结贴了,zcpro说的很详细了。
      

  25.   

    回复niukl:
    test::a的地址不是对齐的
      

  26.   

    这里有这样一个问题,如果B在多处读取a的值,可能会出现问题。比如:
    if ( a ) // 此时 a != 0.
       strcpy(str_buf, (char*)a);  // 此时a 被A线程改成了 0 or unvalid address.
      

  27.   

    可能会出错,Windows的内存管理采用的是缺页中断机制,也就是说当系统发现程序要访问的数据不在内存中时,会产生一个缺页中断,将存有数据的页面从对换区(外存)调进来。缺页中断不像一般的中断,它在一条指令执行到中间时发生,而一般的中断都不可能在一条指令正在执行时发生,往往要等到一条指令执行结束,再转入中断!
        同时, 如果机器指令长度超过一个字节, 内存寻址又允许间接寻址的话, 一条指令在执行期间最多可能产生6 次中断!
      

  28.   

    我认同 mingbao(★情已逝★) 的解释。
    接下来,我们来讨论一下操作系统如何实现原子操作的吧。
      

  29.   

    在solaris和windows上使用,未出现过错误。缺页中断应该是在指令执行前发生,可以认为是一个trap