關於C 執行順序帶來的一些潛在問題

2022-09-26 01:51:13 字數 2045 閱讀 1674

前言

編寫程式的時候,人們的直觀感覺通常認為,程式的執行順序是按照語句的順序進行的。然而,許多程式語言的規範是允許實際執行順序與語句編寫順序不符的。實際上,編譯器為了完成某種優化,常常會對一些操作進行適當的順序調整,導致一些預料之外的現象。

實驗現象

首先,通過乙個例子來展示這個現象。在乙個c# .net core 3.1命令列程式中,定義兩個全域性變數a和b,**程1中,依次對b和a進行遞增。這樣,在任何時刻b應當等於a或a+1。

static int a = 0;

static int b = 0;

static void thread1()

}**程2中,先讀取a的值,然後執行一些其他操作程式設計客棧,再讀取b的值。如果語句一定是按順序執行的,那麼讀取到的b的值應當比讀取到的a的值更新,從而b必然大於或等於a(除非b發生了溢位)。編寫程式,當b < a時輸出它們的值。

static int c = 0;

static void程式設計客棧 thread2()

b=");}}

}再編寫主程式,啟動上述的兩個執行緒。

static void main(string args)

使用debug配置,編譯並執行該程式,命令列是沒有輸出的,符合我們的預期。但是使用release配置的話,就會出現大量輸出,其中a的值比b大1到5不等。

檢視反彙編可以看到,在第1個c += b語句處,程式將b的值放到了暫存器中,而後面的語句均使用了該暫存器內存放的值。所以,編譯器實際上將對b的讀取操作合併並且前置了。以下為反彙編結果片段。

00007ffb628a394d mov rcx,7ffb6292fbd0h

00007ffb628a3957 mov edx,1

00007ffb628a395c call 00007ffbc2387b10

00007ffb628a3961 mov esi,dword ptr [7ffb6292fc08h]

00007ffb628a3967 mov ecx,esi

00007ffb628a3969 add ecx,dword ptr [7ffb6292fc0ch]

00007ffb628a396f mov dword ptr [7ffb6292fc0ch],ecx

var locala = a;

00007ffb628a3975 mov edi,dword ptr [7ffb6292fc04h]

c += b;

00007ffb628a397b add ecx,esi

c += b;

00007ffb628a397d mov dword ptr [7ffb6292fc0ch],ecx

程式設計客棧 if (locala > localb)

00007ffb628a3983 cmp edi,esi

00007ffb628a3985 jle 00007ffb628a394d

理論分析

在c#語言標準的basic concepts一章execution order一節(參見:basic concepts – c# language specification)中,提到了c#的執行順序規範。c#程式的***在以下關鍵點處的順序是被保留的:

c#程式的執行順序在滿足以下條件的情況下,可以由執行環境任意調整的:

而上述的***包括:

由此可以推出,c#程式中對非volatile變數的讀取順序可能會被調整。在只有乙個執行緒對該變數進行操作時,這個順序的調整是保證不會影響結果的;但如果同時有其他的執行緒正在對變數進行修改,則讀取的順序是無法確定的。

因此,如果有多個執行緒同時訪問的,對值的實時性有要求的變數,應當設定為volatile變數。將上述實驗中的靜態變數a和b改為volatile變數後,即使是release配置下,也不會出現命令列的輸出,即兩個變數的讀取順序符合原始的語句順序。

結論在c#程式中,讀取非volatile變數的順序可能被執行環境任意調整。如果某個變數在被讀取的時候會被其他執行緒寫入,為了該讀取結果的實時性,應vbvcddr當將該變數設定為volatile變數。

總結

ubuntu一些指令碼的執行順序

from 一些優先順序 etc enviroment 系統環境變數 etc profile 使用者環境變數 home profile home env 如果存在 etc bashrc 為每乙個執行bash shell的使用者執行此檔案.當bash被開啟時,該檔案被讀取 bash profile 每個...

ubuntu一些指令碼的執行順序

一些優先順序 etc enviroment 系統環境變數 etc profile 使用者環境變數 home profile home env 如果存在 etc bashrc 為每乙個執行bash shell的使用者執行此檔案.當bash被開啟時,該檔案被讀取 bash profile 每個使用者都可...

ubuntu一些指令碼的執行順序

一些優先順序 etc enviroment 系統環境變數 etc profile 使用者環境變數 home profile home env 如果存在 etc bashrc 為每乙個執行bash shell的使用者執行此檔案.當bash被開啟時,該檔案被讀取 bash profile 每個使用者都可...