home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.lang.c++.moderated      Moderated discussion of C++ superhackery      33,346 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 32,863 of 33,346   
   fmatthew5876 to All   
   atomics and memory model: The release se   
   16 Feb 13 19:56:22   
   
   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)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca