2017-04-11 76 views
1

所以我需要一個線程池用於我的應用程序,這導致我創建一個std::map<int, std::thread>對象。 我遇到一些很意外的行爲,這可以簡化爲這樣:使用std :: thread使用std :: map的意外行爲

std::map<int, std::thread> threads; 

threads.insert(std::pair<int, std::thread>(1, std::thread([]() { 
     std::cout << "I'm the first thread and I'm gonna work\n"; 
    }))); 
threads[1].join(); 

std::cout << "Thread 1 joinable? " << threads[1].joinable() << "\n"; 

threads.insert(std::pair<int, std::thread>(1, std::thread([]() { 
     std::cout << "I'm not gonna work at all\n"; 
    }))); 
threads[1].join(); 

輸出是

I'm the first thread and I'm gonna work 
Thread 1 joinable? 0 

後立刻std::terminate()被調用,程序接收SIGABRT信號。

現場調試提示terminate被調用,因爲joinable()是真的,但我只是檢查,並認爲它不是!

而且,要克服它只是後join() ING添加以下行的方式:

threads.erase(1); 

這讓我有點困惑,因爲它看起來像的std::thread一個新的實例是前剛剛創造了我insert打電話...有人可以提示我這種意外的行爲嗎?

+0

在stdout上跟蹤時,不要忘記刷新。 – molbdnilo

+0

@molbdnilo - 換行符應該這樣做。 –

+0

@OliverCharlesworth''\ n''不會刷新'std :: cout'。 –

回答

4

http://en.cppreference.com/w/cpp/container/map/insert

插入元件(多個)放入容器中,如果容器沒有包含具有等效鍵的元素。

您的地圖已包含在關鍵1所以第二threads.insert一個元素沒有做任何事情。你只是試圖加入兩次相同的std::thread。這就是爲什麼threads.erase(1);解決了問題,您的地圖不再包含關鍵字1的線程。

+0

太好了,謝謝。所以沒有直接的API來覆蓋現有的密鑰,我說得對嗎? –

+0

@OmerPerry'treads [1] = std :: thread([](){/ * do work * /});'將會用新的'覆蓋'主鍵'1'處的線程。沒有方法可以在單次調用中刪除然後替換元素,但移動分配對任何可移動類型都應該做同樣的事情。 –

相關問題