2017-08-31 79 views
0

我想推送隊列中的lambda。這個lambda會被強制執行到另一個線程中。而當前線程將等待,直到執行拉姆達,返回一些結果:將lambda推送到C++ STL隊列導致分段錯誤

void * EglThread::execute(const std::function<void *()> f) { 
    std::condition_variable lambdaExecutedCond; 
    void * out; 
    bool exceptionFlag = false; 
    std::exception exception; 

    std::unique_lock<std::mutex> lk(this->mutex); 
    this->queue.push([&]() -> void { 
     std::unique_lock<std::mutex> __unused lock(this->mutex); 
     lambdaExecutedCond.notify_one(); 

     try { 
      out = f(); 
     } catch (const std::exception & e) { 
      exceptionFlag = true; 
      exception = e; 
     } 
    }); 
    this->cond.notify_all(); 
    lambdaExecutedCond.wait(lk); 

    if (exceptionFlag) { 
     throw exception; 
    } else { 
     return out; 
    } 
} 

void EglThread::run() { 
    while (true) { 
     std::unique_lock<std::mutex> lk(this->mutex); 
     if (this->queue.empty()) { 
      if (this->flagShutdown) { 
       break; 
      } else { 
       this->cond.wait(lk); 
      } 
     } else { 
      this->queue.front()(); 
      this->queue.pop(); 
     } 
    } 
} 

但我push操作過程中遇到分段錯誤。日誌看起來像:

EglThread::execute(). 

Queue pushing... 

Segmentation fault 

而我不知道什麼是錯的。 queue將對象聲明爲類成員,但不對其構造函數進行明確調用。就像這樣:

std::queue<std::function<void()>> queue; 
+2

我不知道爲什麼它失敗了,但是你應該很高興它失敗的那麼早:當你運行它時,lambda實際上不會工作,因爲它通過引用捕獲'mutex'。當你從隊列中運行lambda時,互斥量就會超出範圍。 – dasblinkenlight

+0

根據MCVE構建您的問題肯定會爲您提供答案。我們無法編譯不完整的代碼片段。 https://stackoverflow.com/help/mcve –

+0

@dasblinkenlight爲什麼'互斥'將超出範圍?創建lambda的方法將不會完成,直到lambda被執行。所以所有的局部變量都是「活着的」 –

回答

1

的例子(簡體)尋找:

Log<ANDROID_LOG_INFO>("Queue pushing...\n"); 
this->queue.push([&]() -> void { /*...*/ }); 
Log<ANDROID_LOG_INFO>("Queue pushed\n"); 

我們可以看到,這個問題是關於queue.push一部分。 這是你應該關注的。

所以可能的原因是:

  1. queue被incorrrectly初始化,
  2. 創建拉姆達「對象」,一些數據可以被複制,這是造成該段故障期間。

對於第一個原因,我做了一個最小的例子重複您的代碼: 差異是我把隊列放入函數。

void execute(const std::function<void*()> f) 
{ 
    std::queue<std::function<void*()>> queue; 

    queue.push([ & ]() -> void* 
    { 
     return f(); 
    }); 
} 

int main() 
{ 
    execute([]() -> void* 
    { 
     return nullptr; 
    }); 
} 

這工作沒問題。但是這是單線程的!需要來自您的更多信息來解釋如何/何時執行這些功能。尤其是比賽條件。

只因爲你使用互斥體,並不意味着你是安全的。

第二個原因更難追蹤。

爲了調試,在lambda內部,我會逐個註釋每一行,看看這是否有助於克服分段錯誤。 然後我們可以更容易地找到原因。

+0

謝謝你的幫助!我發現,造成的問題是'queue'對象。如果我創建一個本地'隊列'變量,就像你的例子,'queue.push()'工作正常。但是,如果我嘗試使用隊列,這是類的成員,我得到了段錯誤。所以,我不用任何特殊的方式初始化它。它只是宣佈爲私人領域(正如我在quastion中所描述的)。什麼可能是錯誤? –

+0

我發現了這個問題。它是由在outter類中的構造函數中創建字段的順序造成的 –