2016-08-24 44 views
3

我使用VS2015,並且在使用std :: thread時遇到了一個非常奇怪的問題。std :: thread在使用參數創建時拋出訪問衝突異常?

void Klass::myfunc(int a, int b) { std::cout << a << ' ' << b << std::endl; } 
// ... 
auto t = std::thread(&Klass::myfunc, this, 100, 200); <- runtime error after called 
// ... 
t.join(); 

它運作良好,在調試模式,而是拋出一個「訪問衝突異常」當我打開來釋放模式。

更重要的是,如果我嘗試修改 「MYFUNC」 這樣的:

void Klass::myfunc() { std::cout << "foo" << std::endl; } 
// ... 
auto t = std::thread(&Klass::myfunc, this); // everything goes well 
// ... 
t.join(); 

一遍效果很好。

我保證「& Klass :: myfunc」和「this」指針不爲NULL。當ctor被呼叫時,在幾行後有一個「加入」。

我想這可能是某種「未定義的行爲」,但我不知道它到底是什麼。

調用堆棧是這樣的:

000000c83a4ffd40() Unknown 
> distributed_word_embedding.exe!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl multiverso::Communicator::*)(void) __ptr64,multiverso::Communicator * __ptr64>,std::default_delete<std::tuple<void (__cdecl multiverso::Communicator::*)(void) __ptr64,multiverso::Communicator * __ptr64> > > >::_Run(std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl multiverso::Communicator::*)(void),multiverso::Communicator *>,std::default_delete<std::tuple<void (__cdecl multiverso::Communicator::*)(void),multiverso::Communicator *> > > > * _Ln) Line 247 C++ 
    distributed_word_embedding.exe!std::_Pad::_Call_func(void * _Data) Line 210 C++ 
    ucrtbase.dll!00007ffabdc7be1d() Unknown 
    kernel32.dll!00007ffabfae8102() Unknown 
    ntdll.dll!00007ffac26bc5b4() Unknown 
+6

你做線程後會發生什麼?你會加入嗎? – doctorlove

+3

@doctorlove可能暗示的是,這看起來像一個生命期問題,其中線程超過了Klass實例,因此有一個懸空的指針。通過加入正確的地方,你可以防止這一點。然而,我們無法確定基於所呈現的情況。 – stefaanv

+0

@doctorlove stefaanv嗨,謝謝你的回覆。實際上,調試器和日誌顯示程序在調用std :: thread的ctor後立即停止,並且「join」之後是幾行。我認爲問題不在於「加入」。而且我在這個問題中還提到,如果我不帶任何參數地稱呼「myfunc」,那麼一切都會順利。 – Wizmann

回答

1

你應該始終確保你加入(或可能分離)一thread,否則留下main尤其是使用對象的線程(在這種情況下this)會(有時)會導致問題。

//... details omitted... 

int main() 
{ 
    auto t = std::thread(&Klass::myfunc, this); 
    t.join(); //<----- NOTE THIS 
} 

安東尼威廉的穿線blog經過這個詳細。用一個例子非常相似,你的第二個:

void my_thread_func() 
{ 
    std::cout<<"hello"<<std::endl; 
} 

int main() 
{ 
    std::thread t(my_thread_func); 
} 

他說

如果你編譯並運行這個小應用程序時,會發生什麼?是否 打印你好我們想要的?那麼,實際上沒有說服力。它可能會做,也可能不會。我在我的機器上多次運行這個簡單的應用程序 ,並且輸出不可靠:有時它輸出 「hello」,換行符;有時它會在沒有 換行符的情況下輸出「hello」,有時它不輸出任何內容。那是怎麼回事? 這樣一個簡單的應用程序當然應該表現可預測?

隨後,他介紹了一種用join正如我上面做的想法,並說,

的問題是我們沒有等待我們的線程來完成。當 執行到達main()的末尾時,程序終止, 無論其他線程在做什麼。