2012-07-25 113 views
4

我在2個線程之間共享一個變量。我使用volatile來避免優化。函數沒有volatile。怎麼修?

但是,它顯示了在strcpy中沒有volatile的錯誤。 (如下)

我該如何解決這個錯誤?

有些人告訴我要打掉揮發性物質。 但是,如果我拋棄易失性,那麼我失去了易失性的目的.... 和最終可能會得到一個運行時錯誤優化.....是不是?

非常感謝。

(代碼可以直接編譯)


CRITICAL_SECTION CriticalSection; 

HANDLE hEvent; 

void __cdecl MyThread(void* name) 

{ 

char serName[256]; 

volatile char* vptr = (char*) name; 



EnterCriticalSection(&CriticalSection); 



strcpy(serName, vptr); // error : cannot convert 'volatile' 

// use (and not modify) name… 



LeaveCriticalSection(&CriticalSection); 

SetEvent (hEvent) ; 

} 




void main() 

{ 

char name[256] = "abcde"; 

hEvent = CreateEvent (NULL, false, false, NULL) ; 

if (!InitializeCriticalSectionAndSpinCount(&CriticalSection, 0x80000400)) 

return; 



_beginthread (MyThread, 0, name) ; 



EnterCriticalSection(&CriticalSection); 

// access name… 

LeaveCriticalSection(&CriticalSection); 



WaitForSingleObject (hEvent, INFINITE) ; 

DeleteCriticalSection(&CriticalSection); 

CloseHandle (hEvent); 

system("pause"); 

} 

在另一方面,我可以寫我自己的strcpy支持揮發。 但這很奇怪。 因爲如果是這樣的話,那麼我每次使用volatile都必須編寫自己的I/O流(或那些複雜的函數)?

Thx a再次回答。

+1

簡單的回答:刪除'volatile'。在任何情況下你想避免哪種優化? – 2012-07-25 05:15:34

+2

順便說一句,揮發性不利於線程安全。 – 2012-07-25 05:22:35

+0

@Yochai:在Visual C++中它有,而且這個問題是如此標記的。 – 2012-07-25 05:38:14

回答

4

顯然你不清楚「volatile」是什麼意思。意思是或多或少「嘿,編譯器,請注意,別人會改變這個變量,所以你不能假設,除非你的代碼寫它的價值將保持不變,而另一些人可能在看這個變量,所以當我寫信給這個變量請不要做那些無關緊要的假設,因爲對於那些注意事項的人來說,所以只要寫下我希望你寫的東西,並且當我告訴你這麼做的時候。「

何時使用「易揮發?這是一個常見的例子:

volatile int stopflag; // flag will be set by an interrupt handler 

void mainloop() 
{ 
    stopflag = 0; 
    while (!stopflag) 
    { 
     ... 
    } 
} 

如果在三個點的代碼不會接觸stopflag,從不調用帶有一個未知的實現,那麼編譯器可能會傾向於避免讀取標誌的循環,因爲看的功能代碼本身,似乎根本沒有必要讀取變量......只需設置並永久循環即可。

另一種情況可能是:

extern volatile unsigned char outloc; // monitored by hardware 

... 
// emit a wave pulse 
for (int x=0; x<256; x++) 
    outloc = x; 

這裏沒有volatile編譯器可能會傾向於只寫0xFF的位置,而不是寫所有的中間值。

請注意,在現代硬件上使用volatile進行線程同步是不夠的。在今天的計算機中,CPU通常是多核的,因此寫入和讀取不再是原子操作。在過去(在單核CPU上),實際上通常可以使用易失性變量來進行線程同步,現在這是錯誤的。

你似乎在告訴該緩衝確實正在讀取和別人寫的確實有興趣,但在這種情況下,因此在一個函數的任何呼叫(除非它內聯緩衝區的地址是公共或具有已知的實現代碼)編譯器必須假定緩衝區內容可能已經改變或將被未知代碼讀取。

我敢打賭,以適當的方式聲明線程同步原語以確保在您的情況下也是如此(即使strcpy已內聯)。

+0

@CharlesBailey:呃。你是對的。固定。 – 6502 2012-07-25 06:47:49

+0

「你似乎確實有興趣告訴緩衝區確實被其他人閱讀和寫入」<----是的,這就是我的想法! – KenC 2012-07-25 08:25:00

0

我可以理解,在某些地方(使用線程時),我們不希望進行優化,因此我們使用「volatile」關鍵字。

參見MSDN

申報對象由指針爲const或揮發性指出,使用以下形式的聲明:

const char *cpch; 
volatile char *vpch; 

申報指針的值 - 即,在指針中存儲的實際地址 - 爲const或易揮發,使用形式的聲明:

char * const pchc; 
char * volatile pchv; 

所以,你可以使用(根據您的需求)

"strcpy(serName, (char *)vptr);" or " char* volatile vptr = (char*) name;" 

以上是您的代碼通過抑制優化運行並且不會產生任何錯誤的解決方案。現在您將不需要自己實現完整的I/O :)

這對我很有用。希望它可以幫助你...