關於c中volatile關鍵字

來源:互聯網
上載者:User

標籤:style   blog   http   java   使用   os   

一個定義為volatile的變數是說這變數可能會被意想不到地改變,這樣,編譯器就不會去假設這個變數的值了。精確地說就是,最佳化器在用到這個變數時必須每次都小心地重新讀取這個變數的值,而不是使用儲存在寄存器裡的備份。下面是volatile變數的幾個例子:
    1). 平行裝置的硬體寄存器(如:狀態寄存器)
    2). 一個中斷服務子程式中會訪問到的非自動變數(Non-automatic variables)
    3). 多線程應用中被幾個任務共用的變數
    回答不出這個問題的人是不會被僱傭的。我認為這是區分C程式員和嵌入式系統程式員的最基本的問題。嵌入式系統程式員經常同硬體、中斷、RTOS等等打交道,所用這些都要求volatile變數。不懂得volatile內容將會帶來災難。
    假設被面試者正確地回答了這是問題(嗯,懷疑這否會是這樣),我將稍微深究一下,看一下這傢伙是不是直正懂得volatile完全的重要性。
    1). 一個參數既可以是const還可以是volatile嗎?解釋為什麼。
    2). 一個指標可以是volatile 嗎?解釋為什麼。
    3). 下面的函數有什麼錯誤:
         int square(volatile int *ptr)
         {
              return *ptr * *ptr;
         }
    下面是答案:
    1). 是的。一個例子是唯讀狀態寄存器。它是volatile因為它可能被意想不到地改變。它是const因為程式不應該試圖去修改它。
    2). 是的。儘管這並不很常見。一個例子是當一個中服務子程式修該一個指向一個buffer的指標時。
    3). 這段代碼的有個惡作劇。這段代碼的目的是用來返指標*ptr指向值的平方,但是,由於*ptr指向一個volatile型參數,編譯器將產生類似下面的代碼:
    int square(volatile int *ptr)
    {
         int a,b;
         a = *ptr;
         b = *ptr;
         return a * b;
     }
    由於*ptr的值可能被意想不到地該變,因此a和b可能是不同的。結果,這段代碼可能返不是你所期望的平方值!正確的代碼如下:
     long square(volatile int *ptr)
     {
            int a;
            a = *ptr;
            return a * a;
     }
     
    
    
Volatile 關鍵字告訴編譯器不要持有變數的臨時性拷貝。一般用在多線程程式中,以避免在其中一個線程操作該變數時,將其拷貝入寄存器。請看以下情形:

   A線程將變數複製入寄存器,然後進入迴圈,反覆檢測寄存器的值是否滿足一定條件(它期待B線程改變變數的值。
在此種情況下,當B線程改變了變數的值時,已改變的值對其在寄存器的值沒有影響。所以A線程進入死迴圈。
  
   volatile 就是在此種情況下使用。
 

What does volatile do?


This is probably best explained by comparing the effects that volatile and synchronized have on a method. volatile is a field modifier, while synchronized modifies code blocks and methods. So we can specify three variations of a simple accessor using those two keywords:

         int i1;              int geti1() {return i1;}
volatile int i2; int geti2() {return i2;}
int i3; synchronized int geti3() {return i3;}

geti1() accesses the value currently stored in i1 in the current thread. Threads can have local copies of variables, and the data does not have to be the same as the data held in other threads. In particular, another thread may have updated i1in it‘s thread, but the value in the current thread could be different from that updated value. In fact Java has the idea of a "main" memory, and this is the memory that holds the current "correct" value for variables. Threads can have their own copy of data for variables, and the thread copy can be different from the "main" memory. So in fact, it is possible for the "main" memory to have a value of 1 for i1, for thread1 to have a value of 2 for i1 and for thread2 to have a value of 3 for i1 if thread1 and thread2 have both updated i1 but those updated value has not yet been propagated to "main" memory or other threads.


On the other hand, geti2() effectively accesses the value of i2 from "main" memory. A volatile variable is not allowed to have a local copy of a variable that is different from the value currently held in "main" memory. Effectively, a variable declared volatile must have it‘s data synchronized across all threads, so that whenever you access or update the variable in any thread, all other threads immediately see the same value. Of course, it is likely that volatile variables have a higher access and update overhead than "plain" variables, since the reason threads can have their own copy of data is for better efficiency.


Well if volatile already synchronizes data across threads, what is synchronized for? Well there are two differences. Firstlysynchronized obtains and releases locks on monitors which can force only one thread at a time to execute a code block, if both threads use the same monitor (effectively the same object lock). That‘s the fairly well known aspect to synchronized. But synchronized also synchronizes memory. In fact synchronized synchronizes the whole of thread memory with "main" memory. So executing geti3() does the following:



  1. The thread acquires the lock on the monitor for object this (assuming the monitor is unlocked, otherwise the thread waits until the monitor is unlocked). 
  2. The thread memory flushes all its variables, i.e. it has all of its variables effectively read from "main" memory (JVMs can use dirty sets to optimize this so that only "dirty" variables are flushed, but conceptually this is the same. See section 17.9 of the Java language specification). 
  3. The code block is executed (in this case setting the return value to the current value of i3, which may have just been reset from "main" memory). 
  4. (Any changes to variables would normally now be written out to "main" memory, but for geti3() we have no changes.) 
  5. The thread releases the lock on the monitor for object this.

So where volatile only synchronizes the value of one variable between thread memory and "main" memory, synchronized synchronizes the value of all variables between thread memory and "main" memory, and locks and releases a monitor to boot. Clearly synchronized is likely to have more overhead than volatile.

 

http://blog.csdn.net/daniel_ice/article/details/7222547

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.