Безопасно ли создавать новый поток в цикле?
Можно ли создать новый поток внутри цикла? Я пробовал этот путь:
std::thread thread(ClientLoop,clientSocket)
Но как только функция возвращает его, она выдает ошибку.
while (true){
cout << "Waiting for new connections" << endl;
clientSocket = accept(listenSocket, nullptr, nullptr);
cout << "Client connected" << endl;
new thread(ClientLoop,clientSocket);
}
Таким образом, это работает, но мне интересно, нет ли утечек памяти. Спасибо.
Ответы
Ответ 1
как только функция возвращает его, выдается ошибка
В самом деле, вы не должны уничтожать объект соединяемого потока. Если вам не нужно ждать завершения потока позже, отделите его:
std::thread thread(ClientLoop,clientSocket);
thread.detach();
// OK to destroy now
Если вам нужно будет присоединиться к нему позже, вам придется хранить его где-то, что сохраняется за пределами цикла, например
std::vector<std::thread> threads;
while (whatever){
clientSocket = accept(listenSocket, nullptr, nullptr);
threads.emplace_back(ClientLoop,clientSocket);
}
// later
for (std::thread & t : threads) {
t.join();
}
// OK to destroy now
threads.clear();
Таким образом, он работает, но мне интересно, нет ли утечек памяти.
Да, это утечка. Каждый new
создает объект потока, и вы удаляете указатель, не удаляя его, или присваиваете его умному указателю, который нужно позаботиться. Как упоминалось в комментариях, это не только утечка памяти, но и ручки потоков, которые на некоторых системах являются более скудным ресурсом; поэтому через некоторое время вы обнаружите, что не можете запускать больше потоков.
Отсоединение потока - это способ оставить его работающим в фоновом режиме без утечки. Это заставляет поток выделять свои ресурсы, когда он заканчивается.
Ответ 2
Нет проблем с созданием потока в цикле, но
быть проблемой, разрушающей его в конце цикла, если это
локальная переменная. Чтобы быть юридически разрушенным, объект потока
должен быть detach
ed, join
ed или перемещен. Если ваши потоки
просто "огонь и забыть", и вам никогда не придется
синхронизироваться с ними позже (даже для чистого выключения), затем
просто вызовите std::thread::detach
в потоке после его создания.
В противном случае вы можете поместить его в std::vector<std::thread>
, поэтому
что вы можете найти его и присоединиться к нему иногда позже.
Ответ 3
похоже, что вы не хотите управлять временем жизни потока (это почти всегда ошибка).
Если вы действительно хотите это сделать, это будет сделано следующим образом:
while (true){
cout << "Waiting for new connections" << endl;
clientSocket = accept(listenSocket, nullptr, nullptr);
cout << "Client connected" << endl;
thread t(ClientLoop,clientSocket);
t.detach(); // detach the actual thread from its std::thread handle
}