Path: csiph.com!x330-a1.tempe.blueboxinc.net!usenet.pasdenom.info!aioe.org!eternal-september.org!feeder.eternal-september.org!.POSTED!not-for-mail From: Alexander Terekhov Newsgroups: comp.programming.threads Subject: Re: C++0x, 29.3 p13 "[...] atomic stores visible [...] within a reasonable amount of time." Date: Mon, 27 Jun 2011 20:55:41 +0200 Organization: A noiseless patient Spider Lines: 86 Message-ID: <4E08D22D.7EB751FB@web.de> References: <3c50710c-c220-4697-91a7-49b6dc304782@r33g2000prh.googlegroups.com> Reply-To: terekhov@web.de Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Injection-Info: mx04.eternal-september.org; posting-host="MCbSEzW5qwGLFMNXJh39IQ"; logging-data="31662"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19/2uyPRF0/+LX06QFsaNKFDmbhtm9VMos=" X-Mailer: Mozilla 4.77 [en] (Windows NT 5.0; U) X-Accept-Language: en Cancel-Lock: sha1:AHO2AyGQUe8Z23IgA2KeHHcozYk= Xref: x330-a1.tempe.blueboxinc.net comp.programming.threads:367 Joshua Maurice wrote: > > I have a question regarding C++0x, 29.3 p13. In draft n3242, the exact > text is: > > "Implementations should make atomic stores visible to atomic loads > within a reasonable amount of time." > > I am wondering if there is a well known intent as to the meaning of > "reasonable". Allow me to explain. I apologize up front if I'm > mistaken in any of my understandings, and please point out any such > misunderstandings. I also understand this is a QoI issue, but I think > that this particular answer greatly affects how one should write > portable code, which is why it's not quite something we ought to be > allowed to handwave as "implementation defined". > > Consider: > std::atomic x; > //... > while(x.load(std::memory_order_relaxed)) {} > That is, suppose we have an atomic variable x, and perhaps > specifically the type which is guaranteed to be lock-free. (I can't > quite find the text for that offhand.) It's my understanding that the > intent is for that load to be implemented by whatever passes for the > normal, common assembly load on that platform. > > So, that simple assembly load may be satisfied by a core local cache. > If it is satisfied by a core-local cache, then the changes are high in > that busy waiting loop that future loads will be satisfied by a core > local cache, and thus it may not see a new write, ever, barring other > things. Other things, such as the common multi-tasking, preemptive > threading, OS. For that, eventually that busy loop will exhaust the > thread's timeslice, and it will be taken off the core. At some later > point, it will be put back on the core, which as I understand commonly > invalidates any core local caches, which means that the next load of > that busy waiting loop will go to main memory (or non-core local > cache, etc.), and it will see a new value. > > So, would such an implementation be "conforming in spirit"? I > understand this is a QoI issue, but it is relevant. Specifically, is > there some understood intent and meaning that "reasonable" means > "maybe the next time the thread is scheduled out and scheduled back > in", or is "reasonable" meant to be something sooner than that? > > This may be relevant to real world code for cooperative thread > cancelling. I assume the default way of handling cooperative thread > cancelling is to have a lock-free std::atomic bool variable which is > global to the "job" which can be cancelled. Call that the "stop flag". > Threads doing the jobs will periodically check the stop flag, and if > read true, then they will bail out and end the job. The question is > whether the stop flag should use memory_order_relaxed loads and stores > or seq_cst loads and stores. If relaxed loads and stores can be > delayed until the thread is scheduled out and back in, then that may > be too high of a delay for responsive cooperative job cancellation. > It's my understanding that with seq_cst loads and stores to the stop > flag, then that cannot be delayed by anything more than a "few" > assembly instructions, due to the total order S. C++11 aside (the latest draft is not public and I have no idea what it says), on assembly level, in order to read the last value you need read-modify-write operation such as fetch_add(0) and relaxed RMW reads last value just fine. > > Of course, in practice, on "normal desktop processors", for non- > trivial code aka code which isn't just a busy waiting loop like above, > I expect that the caches will eventually get flushed, probably usually > much before a thread exhausts its timeslice, so the above reasoning is > rare worst case scenario. Perhaps it's still practical to use relaxed > loads and stores for the stop flag, despite the low probability > possibility that the stop flag may be delayed a very long time? > > Then again, what about more exotic architectures, like NUMA > processors? How would that interact with this? I am woefully ignorant > on such details, and that is why I ask. Does C++0x, 29.3 p13 require > some intelligence from the compiler so that the compiler must > implement relaxed loads and stores as something more than the simple > assembly loads and stores? Perhaps most are simple assembly loads and > stores, but the compiler puts whatever assembly magic in loops and > here and there to fulfill the "within reasonable amount of time" > guarantee? regards, alexander.