2014-09-12 23 views
2

我遇到了由std :: async啓動的進程的一些問題。C + + std ::異步調用類成員方法不會看到變量更改

class BaseClass { 
public: 
    BaseClass() {enabledFlag = false;} 
    virtual ~BaseClass() {} 

protected: 
    int process(); 
    bool enabledFlag; 
}; 


int BaseClass::process() { 
    int rc = -1; 
    if (enabledFlag == false) { 
     std::cout << "Not enabled\n" << std::flush; 
     return rc; 
    } 

    rc = 0; 
    while (enabledFlag) { 
     // this loop should set rc to be something other than zero if an error is to be signalled 
     // otherwise loop here doing stuff until the user sets enabledFlag=false 
    } 

    return rc; 
} 

class DerivedClassWithExposedMembersForTesting : public BaseClass { 
public: 
    using BaseClass::enabledFlag; 
    using BaseClass::process; 

}; 

在我的谷歌測試測試:

TEST(FixtureName, process_exitsWithRC0_WhenEnabledFlagSetTrueDuringExecution { 
    DerivedClassWithExposedMembersForTesting testClass; 
    testClass.enabledFlag = true; 

    // print status 
    std::cout << "Enabled: " << testClass.enabledFlag << std::endl << std::flush; 

    std::future<int> returnCodeFuture = std::async(std::launch::async, &DerivedClassWithExposedMembersForTesting::process, &testClass); // starts background execution 
    // set flag to false to kill loop 
    testClass.enabledFlag = false; 

    int rc = returnCodeFuture.get(); 

    EXPECT_EQ(0, rc); 
} 

我的std ::異步的理解是,它訂於不久後運行調用異步和執行的主線程將阻塞如果線程尚未完成,則在get()調用。對get()的調用將返回process()的返回值。

如果testClass未啓用,process()被設置爲不運行,因此我在測試中啓用它。

我希望看到:

Enabled: 1 
// test passes 

我看到的是:

Enabled: 1 
Not enabled 
// test fails 
Failure 
Value of: rc 
    Actual: -1 
    Expected: 0 

爲什麼過程的std ::觸發異步沒有看到由主設定的enabledFlag的價值進行異步調用之前的進程?

注:enabledFlag應該從外部過程中設置,一般不從內環路,因此這種結構

** **更新 按我的意見,我通過將它固定以下行測試,只是後調用異步():

// Use wait_for() with zero milliseconds to check thread status; delay until it has started 
while (returnCodeFuture.wait_for(std::chrono::milliseconds(0)) == std::future_status::deferred) {} 
+1

不要使用非'原子'進行線程間通信。 – 2014-09-12 13:02:29

+0

對不起,@JoachimPileborg,在複製代碼時發生錯誤。現在修復。 – John 2014-09-12 13:06:53

+1

兩個線程可能同時訪問'testClass.enabledFlag',其中一個線程修改它。這是*數據競爭*的定義; C++沒有定義數據競爭程序的行爲。您必須使用互斥鎖或將其聲明爲原子(即,std :: atomic ')來同步對'testClass.enabledFlag'的訪問。 – Casey 2014-09-12 19:07:49

回答

1

的問題是,你不知道線程運行。在線程實際運行之前,可能只需將標誌設置爲false即可。

解決這個問題的一個簡單方法是讓線程在循環中設置的另一個狀態變量isRunning。你的主線程可以檢查這個線程是否正在運行,然後告訴它結束。

+0

啊,當然,謝謝。我可以看到,如果在調用async()之後給測試添加延遲:for(int i = 0; i <10000; i ++){}代碼按預期執行。 – John 2014-09-12 13:09:15

+2

比隨機延遲更好的是等待只有足夠長的線程才能啓動。在將enableFlag設置爲false之前,我將以下行添加到測試中:while(returnCodeFuture.wait_for(std :: chrono :: milliseconds(0))== std :: future_status :: deferred){} - 這是基於在這個答案在這裏:http://stackoverflow.com/questions/9094422/how-to-check-if-a-stdthread-is-still-running – John 2014-09-12 13:23:39

相關問題