zoukankan      html  css  js  c++  java
  • Main purposes of C# Volatile fields

    Introduction

    The article describes the internals of volatile fields. I've seen a lot of discussions in the web regarding volatile fields. I've performed my own small research in this area, and here are some thoughts on this.

    Volatile fields and memory barrier: A look inside

    The two main purposes of C# volatile fields are:

    1. Introduce memory barriers for all access operations to these fields. In order to improve performance, CPUs store frequently accessible objects in the CPU cache. In the case of multi-threaded applications, this can cause problems. For instance, imagine a situation when a thread is constantly reading a boolean value (read thread) and another one is responsible for updating this field (write thread). Now, if the OS will decide to run these two threads in different CPUs, it is possible that the update thread will change the value of the field on the CPU1 cache and the read thread will continue reading the value from the CPU2 cache. In other words, it will not get the change in thread1 until the CPU1 cache is invalidated. The situation can be worse if two threads update the value.

      Volatile fields introduce memory barriers, which means that the CPU will always read from and write to the virtual memory, but not to the CPU cache. Nowadays, such CPU architectures as x86 and x64 have CPU cache coherency, which means that any change in the CPU cache of one processor will be propagated to other CPU caches. And, in its turn, it means that the JIT compiler for the x86 and x64 platforms makes no difference between volatile and non-volatile fields (except the one stated in item #2). Also, multi-core CPUs usually have two levels of cache: the first level is shared between CPU cores, and the second one is not. But, such CPU architectures as Itanium with a weak memory model does not have cache coherency, and therefore thevolatile keyword and memory barriers play a significant role while designing multi-threaded applications. Therefore, I'd recommend to always use volatile and memory barriers even for x86 and x64 CPUs, because otherwise, you introduce CPU architecture affinity to your application.

      Note: you can also introduce memory barriers by using Thread.VolatileRead/Thread.VolatileWrite(these two methods successfully replace the volatile keyword), Thread.MemoryBarrier, or even with the C# lock keyword etc.

      Below are displayed two CPU architectures: Itanium and AMD (Direct Connect architecture). As we can see, in AMD's Direct Connect architecture, all processors are connected with each other, so we have memory coherence. In the Itanium architecture, the CPUs are not connected with each other and they communicate with RAM through the System Bus.

     

     

    2. Prevents instruction reordering. For instance, consider we have a loop:

    while(true)
    {
       if(myField)
       {
          //do something
       }

    }

    In the case of a non-volatile field, during JIT compilation, due to performance considerations, the JIT compilercan reorder instructions in the following manner: 
    if(myField)
    {
       while(true)
       {
          //do something
       }

    }

    In case you plan to change myField from a separate thread, will there be a significant difference? Usually, it is recommended to use the lock statement (Monitor.Enter or Monitor.Exit), but if you change only one field within this block, then the volatile field will perform significantly better than the Monitor class. 

    so . that is the why sometimes we need  volatile .but i still have a question about why JIT need reorder the instructions . can anyone tell me why ? thanks a lot . 

    below is the example show how is the volatile keyword happen.

    Compilers use advanced optimizations to reorder instructions in blocks. This improves performance but can cause problems for concurrent threads. Optimizations such as code motion can cause these problems. To alleviate concurrency issues, you can use the volatile modifier on a field: this does not substitute for a locking construct, but can make some code more correct.

    Lock StatementKeywords

    This C# article describes the volatile keyword. Volatile is used in threaded programs.

    Example

     Before we begin, please note that this example isn't ideal in that it would function correctly without the volatile modifier. It serves only to illustrate the concept of the volatile keyword, not to provide a real-world example.

    In the example, there are two static fields—one field is a object reference of string type, and the other is a volatile bool value type. In the Main method, a new thread is created, and the SetVolatile method is invoked. In SetVolatile, both the fields are set.

    Program that uses volatile field [C#]  
    using System; 
    using System.Threading;  
    class Program {     
    static string _result;     
    static volatile bool _done;      
    static void SetVolatile()     
    { 	// Set the string. 
    	_result = "Dot Net Perls"; 	
    // The volatile field must be set at the end of this method. 	
    _done = true;     
    }      
    static void Main()     
    { 	
    // Run the above method on a new thread. 	
    new Thread(new ThreadStart(SetVolatile)).Start();  	
    // Wait a while. 	
    Thread.Sleep(200);  	
    // Read the volatile field. 	
    if (_done) 	
    { 	    
    Console.WriteLine(_result); 	
    }    
     Output  
    Dot Net Perls

     Why is the bool volatile? First of all, the logic in this program is correct even without the volatile modifier on the bool. However, compilers use a lot of optimizations, and some of these optimizations reorder loads and stores from variables.

    When multiple threads execute at once, this can cause serious problems. Please keep in mind that the volatile modifier does not force synchronization of loads and stores; instead it simply tells the compiler not to change the order of accesses to the field. By eliminating reordering optimizations, the code becomes more predictable from a programmer's perspective.

    Correction:Thanks to Robert Paveza for writing in with a correction to this article. It originally contained an incorrect statement—in programming terms, a bug.

    Flags

    The example in this article, adapted from the example in the C# specification itself, demonstrates the concept of a volatile field used as a flag. The bool type is very commonly used as a flag. So when the flag is set to true, you can take other action on that variable.

    The C# Programming Language: Specification

    Performance

    Can volatile fields cause a performance problem if they are used too much? In some cases, this may happen. However, if you are using a volatile field that is accessed in a tight loop millions of times, you can copy it into a regular local variable and then use that local variable: this will provide a performance boost.

    Local Variable Field Optimization

    Tip:

    It's probably a better idea not to use volatile in your programs at all. 

    Summary

     The volatile modifier in the C# programming language provides a way for you to restrict the optimizations the compiler makes regarding loads and stores into the field. Typically, you will use volatile in multithreaded programs and with flag variables. The volatile keyword does not substitute for the lock statement; it merely restricts certain optimizations that could cause a multithreaded program to behave incorrectly.


  • 相关阅读:
    Codeforces Round #657 (Div. 2) 题解
    洛谷 P2765 魔术球问题 (最小路径覆盖 or 贪心)
    洛谷 P2472 蜥蜴 (最大流)
    Codeforces Round #665 (Div. 2) 题解
    洛谷 P1231 教辅的组成 (三分图匹配,裂点)
    USACO5.4 奶牛的电信Telecowmunication (最小割,割边转割点)
    有关网络流的一些板子题
    洛谷 p2756 飞行员配对方案问题(最大流,二分图匹配)
    JSON.toJSONString中序列化空字符串遇到的坑
    关于mysql自动备份的小方法
  • 原文地址:https://www.cnblogs.com/malaikuangren/p/2533447.html
Copyright © 2011-2022 走看看