Volatile (computer programming): Difference between revisions

Content deleted Content added
expand
Eindiran (talk | contribs)
Add new source for section on C#
Line 233:
==In C#==
 
In [[C Sharp (programming language)|C#]], <code>volatile</code> ensures that code accessing the field is not subject to some thread-unsafe optimizations that may be performed by the compiler, the CLR, or by hardware. OnlyWhen a field is marked <code>volatile</code>, the followingcompiler typesis caninstructed beto markedgenerate volatile:a all"memory referencebarrier" types,or Single,"fence" Boolean,around Byteit, SByte,which Int16,prevents UInt16,instruction Int32,reordering UInt32or caching tied to the field. When reading a <code>volatile</code> field, Charthe compiler generates an ''acquire-fence'', which prevents other reads and allwrites enumeratedto typesthe withfield, anincluding underlyingthose typein ofother Bytethreads, SByte,from Int16,being UInt16,moved Int32''before'' the fence. When writing to a <code>volatile</code> field, orthe UInt32compiler generates a ''release-fence''; this fence prevents other reads and writes to the field from being moved ''after'' the fence.<ref name="Albahari">{{cite bookweb |last1=RichterAlbahari |first1=JeffreyJoseph |title=CLRPart Via4: Advanced Threading |url=http://www.albahari.com/threading/part4.aspx#_Nonblocking_Synchronization |website=Threading in C# |publisher=MicrosoftO'Reilly PressMedia |dateaccessdate=February9 11,December 20102019 |pagesarchiveurl=183 http://www.albahari.info/threading/threading.pdf|chapterarchivedate=Chapter27 7: Constants and FieldsApril 2011|isbnurl-status=978-0-7356-2704-8live}}</ref> (This excludes value [[struct]]s, as well as the primitive types Double, Int64, UInt64 and Decimal.)
 
BasicallyOnly the following types can be marked <code>volatile</code>: isall areference shorthandtypes, for<code>Single</code>, calling<code>Boolean</code>, <code>Thread.VolatileReadByte</code>, and<code>SByte</code>, <code>Thread.VolatileWriteInt16</code>., These<code>UInt16</code>, methods<code>Int32</code>, are<code>UInt32</code>, special. In effect<code>Char</code>, theseand methodsall disableenumerated sometypes optimizationswith usuallyan performedunderlying bytype theof C#<code>Byte</code>, compiler<code>SByte</code>, the<code>Int16</code>, JIT<code>UInt16</code>, compiler<code>Int32</code>, andor the CPU itself<code>UInt32</code>. The methods work as follows:<ref>{{cite book |last1=Richter |first1=Jeffrey |title=CLR Via C# |publisher=Microsoft Press |date=February 11, 2010 |pages=797–803183 |chapter=Chapter 287: PrimitiveConstants Threadand Synchronization ConstructsFields |isbn=978-0-7356-2704-8}}</ref> (This excludes value [[struct]]s, as well as the primitive types <code>Double</code>, <code>Int64</code>, <code>UInt64</code> and <code>Decimal</code>.)
 
*The <code>Thread.VolatileWrite</code> method forces the value in address to be written to at the point of the call. In addition, any earlier program-order loads and stores must occur before the call to VolatileWrite.
Using the <code>volatile</code> keyword does not support fields that are [[Evaluation strategy#Call by reference|passed by reference]] or [[Closure (computer programming)|captured local variables]]; in these cases, <code>Thread.VolatileRead</code> and <code>Thread.VolatileWrite</code> must be used instead.<ref name="Albahari"/>
*The <code>Thread.VolatileRead</code> method forces the value in address to be read from at the point of the call. In addition, any later program-order loads and stores must occur after the call to VolatileRead.
 
*The <code>Thread.MemoryBarrier</code> method does not access memory but it forces any earlier program order loads and stores to be completed before the call to MemoryBarrier. It also forces any later program-order loads and stores to be completed after the call to MemoryBarrier. MemoryBarrier is much less useful than the other two methods.{{Citation needed|date=September 2012}}
In effect, these methods disable some optimizations usually performed by the C# compiler, the JIT compiler, or the CPU itself. The guarantees provided by <code>Thread.VolatileRead</code> and <code>Thread.VolatileWrite</code> are a superset of the guarantees provided by the <code>volatile</code> keyword: instead of generating a "half fence" (ie an acquire-fence only prevents instruction reordering and caching that comes before it), <code>VolatileRead</code> and <code>VolatileWrite</code> generate a "full fence" which prevent instruction reordering and caching of that field in both directions.<ref name="Albahari"/> These methods work as follows:<ref>{{cite book |last1=Richter |first1=Jeffrey |title=CLR Via C# |publisher=Microsoft Press |date=February 11, 2010 |pages=797–803 |chapter=Chapter 28: Primitive Thread Synchronization Constructs |isbn=978-0-7356-2704-8}}</ref>
*The <code>Thread.VolatileWrite</code> method forces the value in addressthe field to be written to at the point of the call. In addition, any earlier program-order loads and stores must occur before the call to <code>VolatileWrite</code> and any later program-order loads and stores must occur after the call.
*The <code>Thread.VolatileRead</code> method forces the value in addressthe field to be read from at the point of the call. In addition, any laterearlier program-order loads and stores must occur afterbefore the call to <code>VolatileRead</code> and any later program-order loads and stores must occur after the call.
 
The <code>Thread.VolatileRead</code> and <code>Thread.VolatileWrite</code> methods generate a full fence by calling the <code>Thread.MemoryBarrier</code> method, which constructs a memory barrier that works in both directions. In addition to the motivations for using a full fence given above, one potential problem with the <code>volatile</code> keyword that is solved by using a full fence generated by <code>Thread.MemoryBarrier</code> is as follows: due to the asymmetric nature of half fences, a <code>volatile</code> field with a write instruction followed by a read instruction may still have the execution order swapped by the compiler. Because full fences are symmetric, this is not a problem when using <code>Thread.MemoryBarrier</code>. <ref name="Albahari"/>
 
==In Fortran==