From: fmatthew5876@googlemail.com   
      
   I've been reading the C++ concurrency in action chapter on the memory model   
   and there is one part I don't quite get in 5.3.4.   
      
   Consider the following modified example from the book   
      
   #include    
   #include    
      
   SomeType data[20];   
   std::atomic count;   
      
      
   void produce() {   
    //Fill up data with some meaningful values   
    count.store(20, std::memory_order_release);   
   }   
      
   void consume() {   
    while(true) {   
    int index;   
    if((index = count.fetch_sub(1,std::memory_order_acquire)) <= 0) {   
    wait_for_more_items();   
    continue;   
    }   
    //Index must be unique, 2 threads cannot get the same index   
    do_something_with_data(data[index-1]);   
    }   
   }   
      
   int main() {   
    std::thread a(produce);   
    std::thread b(consume);   
    std::thread c(consume);   
    a.join();   
    b.join();   
    c.join();   
   }   
      
   So the idea here is that thread a will fill up the data array and   
   then set the number of elements in the array.   
      
   Threads b and c will spin until the count is set and then start consuming   
   unique items in parallel. We don't want threads b and c to ever try to   
   consume the same item.   
      
   Now to me this looks like a bug. The problem being with the line:   
   count.fetch_sub(1,std::memory_order_acquire).   
   fetch_sub is a read-modify-write operation. The acquire assures us it   
   will synchronize with the initial store to 20 from thread a. However there   
   is no release on the store part of the fetch_sub, which to me looks like   
   the store of fetch_sub from thread b will not synchronize with the load of   
   fetch_sub from thread c, allowing a possible situation where both threads   
   b and c could read the same value for index.   
      
   If I were to write this, I would think to use   
   count.fetch_sub(1,std::memory_order_acq_rel).   
      
   However, the use of memory_order_acquire according to the book is in fact   
   correct because of something called the "release sequence."   
      
   >From my limited understanding, a release sequence starts with an initial   
   store with release, acq_rel, or seq_cst and a final load with acquire,   
   consume, or seq_cst. The book says that inside the release sequence you   
   have have any number of read-modify-write operations with *any* memory   
   ordering.   
      
   Can anyone elaborate on why this works? I think I sort of get it but it still   
   seems like voodoo.   
      
      
   --   
    [ See http://www.gotw.ca/resources/clcm.htm for info about ]   
    [ comp.lang.c++.moderated. First time posters: Do this! ]   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|