为什么这个测试应用程序在不同的机器上给出不同 (关于后增量和线程安全)

Ste*_*eve 0 c++ linux multithreading gcc thread-safety

我听说有人说var ++和++ var这样的语句不是线程安全的,所以我写了一个应用程序进行测试.代码如下:

   unsigned long gCounter = 0;
   const unsigned long WORKS = 1048576;  // pow(2, 20)
   const unsigned long MAX_THREADS = 100;
   const unsigned long WORKER_THREADS = 2;

   unsigned long GetCounter(){
           return gCounter++;
   }

   void *WorkerThread(void *){
           unsigned long items = 0;
           do {
                GetCounter();
                items++;
           } while(items < WORKS);

           printf("Exiting thread: %lu\n", pthread_self());
           return NULL;
    }


    int main(int argc, char* argv[]){
         pthread_t workers[MAX_THREADS];

         //create two threads
         for (int i = 0; i < WORKER_THREADS; i++){
            pthread_create(&workers[i], NULL, WorkerThread, NULL);
         }

         //wait for above threads to exit
         for (int i = 0; i < WORKER_THREADS; i++){
               pthread_join(workers[i], NULL);
         }


         assert( gCounter == (WORKER_THREADS * WORKS));
         return 0;
    }
Run Code Online (Sandbox Code Playgroud)

如果后增量操作不是线程安全的,那么上面的测试应用程序有时会失败(可能会成功).但令我惊讶的是,它在我们的服务器上运行时在200次测试中总是成功,而在我的PC上它永远不会成功.

为什么会这样?为什么上面的appcation会一直在我们的服务器上成功?以下是有关服务器和我的电脑的信息:

     Server machine:
     System: Redhat 3.4.2 - 6.FC3  Kernel: LINUX.2.6.10 
     GCC Version: 3.4.2 20041017   
     CPU: AMD Opteron Processor 144 X86_64

     My PC:
     System: ubuntu 3.2.0-40-generic  Kernel: LINUX.3.4
     GCC Version: 4.6.3 (Ubuntu/Linaro )    
     CPU: Intel(R) Pentium(R) Dual  CPU  T2370        

     Build Command (both are the same, turn off optimization)
     g++ -O0 -o test test.cpp -lpthread
Run Code Online (Sandbox Code Playgroud)

更新
今天我发现CPU是AMD Opteron 144的服务器是单CPU单核机器,也许这就是为什么这个测试应用程序永远不会失败的原因.据我所知,单CPU - 单核机器不支持真正的线程并行,线程以非常快的速度运行,它们似乎并行运行,但实际上并非如此,并且一些线程同步问题不是很可能在这种机器上很容易发生.

Man*_*rse 6

您的代码具有未定义的行为,因为它包含数据争用.

[intro.multithread]/21程序的执行包含数据竞争,如果它在不同的线程中包含两个冲突的动作,其中至少有一个不是原子的,并且都不会在另一个之前发生.任何此类数据争用都会导致未定义的行为.

[intro.multithread]/4 如果其中一个修改内存位置(1.7)而另一个访问或修改相同的内存位置,则两个表达式评估会发生冲突.

由于您的代码具有未定义的行为,因此您不能依赖它具有任何特定行为.不要惊讶它总是在一个平台上"工作"而从不在另一个平台上工作.

[defns.undefined] 未定义的行为: 本国际标准不要求的行为.