Подтвердить что ты не робот

Безопасно ли создавать новый поток в цикле?

Можно ли создать новый поток внутри цикла? Я пробовал этот путь:

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);                
}   

Таким образом, это работает, но мне интересно, нет ли утечек памяти. Спасибо.

4b9b3361

Ответ 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
}