一個多線程問題的邏輯思考
阿新 • • 發佈:2017-09-30
llb 但是 理解 cal logs 兩個 才會 進行 col
同事給了一段代碼,用來實現開始錄制聲音和停止錄制,偽代碼如下:
1 void StartRecord() 2 { 3 new Thread() 4 { 5 void run() 6 { 7 m_isRecording = true; 8 Java_StartRecord(); 9 while(m_isRecording == true) 10 { 11 Java_RecordCallback(); 12 } 13 } 14 } 15 } 16 17 void EndRecord()18 { 19 m_isRecording = false; 20 }
StartRecord函數開啟錄制線程,通過m_isRecording 來設置錄制狀態。
初一看這裏沒什麽問題,並且大多數情況下也確實可以正常工作。但是對於特殊的情況,比如StartRecord之後很快調用EndRecord,這時候StartRecord創建了錄制線程,但是錄制線程還沒有開始執行。由於線程調度的不確定性,EndReocord確實存在在錄制線程前執行的情況。這種情況下,EndRecord把m_isRecording 設置為了false,而錄制線程在執行的時候又把m_isRecording 設置成了true,這就回導致錄制線程永遠不會結束。解決這個問題的辦法是改成下面的代碼:
1 void StartRecord() 2 { 3 m_isRecording = true; 4 new Thread() 5 { 6 void run() 7 { 8 Java_StartRecord(); 9 while(m_isRecording == true) 10 { 11 Java_RecordCallback(); 12 } 13 } 14 } 15 } 16 17 void EndRecord() 18 { 19 m_isRecording = false; 20 }
這樣雖然解決了問題,但也應該進行更深入的思考。其關鍵就在於m_isRecording的意義。這裏涉及到了兩個客體,一個是主線程(調用StartRecord和EndRecord的線程),另外一個是錄制線程。在第一段代碼中,EndRecord函數中認為m_isRecording標識主線程的狀態,因為只有主線程才會調用EndRecord函數病修改m_isRecording的值。但是在StartRecord函數中卻是錄制線程修改了m_isRecording的值,同時又在錄制線程中讀取m_isRecording。錄制線程認為m_isRecording表示的是錄制線程的狀態。所以在第一段代碼中,對m_isRecording的理解是存在歧義的。而第二段代碼就非常明確。
暫時理解到這個層次,以後有了更深的理解再記下來。
一個多線程問題的邏輯思考