以前也有人問過類似的問題,但似乎沒有人能解釋我觀察到的一些行為。一些答案已經解釋了為什么您需要擁有指向執行緒的指標向量(復制與移動)。幾個后續問題:
我正在嘗試實體化臨時變數中的指標并將臨時變數推送到向量。它失敗了,但在使用
std::move或將整個實體放入push_back(). 為什么有std::move必要,因為push_back()有 const 參考作為引數,即有什么區別?為什么通過訂閱訪問執行緒會
greeters[i]引發分段錯誤?程式運行了幾次迭代然后崩潰?與上面類似,但帶有迭代器。只有使用
back()似乎作業正常。它與 const 參考回傳型別有什么關系嗎?如果是這樣呢?
編譯使用g -std=c 20 -pthread -o thread thread.cpp.
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
std::mutex m;
int cnt = 0;
void say_hello(int id)
{
m.lock();
cnt ;
std::cout << cnt << " Hello from " << id << std::endl;
m.unlock();
}
int main()
{
int n = 20;
std::vector<std::unique_ptr<std::thread>> greeters(n);
for (int i = 0; i < n; i ) {
// auto tmp = std::unique_ptr<std::thread>(new std::thread( [&i]() { return say_hello(i); } ) );
// greeters.push_back(tmp); // error: no matching function for call to 'construct_at'
// greeters.push_back(std::move(tmp)); // works fine
greeters.push_back(std::unique_ptr<std::thread>(new std::thread( [&i]() { return say_hello(i); } ) )); // works fine
}
for (int i = 0; i < n; i ) {
auto val = std::move(greeters[i]); // throws segmentation fault
// auto val = std::move(greeters.back()); // works fine
// greeters.pop_back();
val -> join();
}
// std::vector<std::unique_ptr<std::thread>>::iterator ptr;
// for (ptr = greeters.begin(); ptr < greeters.end(); ptr ) {
// (*ptr) -> join(); // throws segmentation fault
// }
return 0;
}
uj5u.com熱心網友回復:
該錯誤與向量或執行緒本身無關。建構式是錯誤的。
std::vector<std::unique_ptr<std::thread>> greeters(n);
這將創建一個具有 20 個值的向量,該向量將為空unique_ptrs。
這就是這個建構式所做的。的建構式的n引數std::vector指定向量的初始化大小,它被默認初始化。使用unique_ptrs,默認初始化導致 null unique_ptrs。
for (int i = 0; i < n; i ) {
greeters.push_back...
這最終導致向量再push_back增加 20 個s。unique_ptr它現在有 40unique_ptr秒。其中前二十個是空指標。
for (int i = 0; i < n; i ) {
auto val = std::move(greeters[i]); // throws segmentation fault
val -> join();
}
這將迭代unique_ptr向量中的前 20 秒,其中 a 為空,并嘗試取消參考空 ptrs 以對join它們進行徒勞的嘗試。這以眼淚和分段錯誤告終。
我應該再提一條評論:我也沒有立即看到所示程式中的錯誤。但是我只是在我的除錯器中加載了你的程式,設定了一個斷點,錯誤在幾秒鐘內就變得明顯了:
(gdb) p greeters
$2 = std::vector of length 40, capacity 40 = {std::unique_ptr<std::thread> = {
get() = 0x0}, std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x0},
std::unique_ptr<std::thread> = {get() = 0x418f60},
std::unique_ptr<std::thread> = {get() = 0x419220},
std::unique_ptr<std::thread> = {get() = 0x418f80},
...
為什么這個向量是它應該有的兩倍大,為什么它的前半部分是空unique_ptr的?哦...
這就是為什么花一些時間學習如何使用除錯器以便能夠自己解決這些 Scooby-Doo 謎團是一個好主意的原因。
uj5u.com熱心網友回復:
擺脫所有的間接性。這不是必需的。您可以而且應該創建執行緒向量,而不是經過兩層間接:
[temp]$ cat test.cpp
#include <thread>
#include <vector>
#include <iostream>
int main() {
std::vector<std::thread> vec;
std::thread thr;
vec.push_back(std::move(thr));
std::cout << "Hello, world\n";
return 0;
}
[temp]$ clang -std=c 11 test.cpp
[temp]$ ./a.out
Hello, world
[temp]$
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/412625.html
標籤:
下一篇:使用一兩個引數呼叫模板函式?
