在循环中创建新线程是否安全?

Tom*_*mas 26 c++ multithreading

在循环中创建新线程是否安全?我试过这种方式:

std::thread thread(ClientLoop,clientSocket)
Run Code Online (Sandbox Code Playgroud)

但是一旦函数返回它就会抛出错误.

while (true){
    cout << "Waiting for new connections" << endl;
    clientSocket = accept(listenSocket, nullptr, nullptr);
    cout << "Client connected" << endl;
    new thread(ClientLoop,clientSocket);                
}   
Run Code Online (Sandbox Code Playgroud)

这种方式有效,但我想知道是否没有内存泄漏.谢谢.

Mik*_*our 29

一旦函数返回它就会抛出错误

实际上,您不能销毁可连接的线程对象.如果您以后无需等待线程完成,请将其分离:

std::thread thread(ClientLoop,clientSocket);
thread.detach();
// OK to destroy now
Run Code Online (Sandbox Code Playgroud)

如果你以后需要加入它,那么你必须将它存储在一个持续超出循环的地方,例如

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();
Run Code Online (Sandbox Code Playgroud)

这种方式有效,但我想知道是否没有内存泄漏.

是的,那是漏洞.每个都new创建一个线程对象,您丢弃指针而不删除它或将其指定给智能指针来处理.正如评论中所提到的,它不仅会泄漏内存,还会泄漏线程句柄,这在某些系统上是一种更稀缺的资源; 所以一段时间后你可能会发现你无法启动更多的线程.

分离线程是让它在后台运行而不会泄漏的方法.这会导致线程在完成时释放其资源.

  • 这不仅是内存泄漏.线程通常使用系统资源,直到它们被连接,或者如果它们被分离则终止.在这种情况下,他很有可能在内存不足之前因为线程过多而开始失败. (5认同)

Jam*_*nze 9

在循环中创建线程没有问题,但如果它是局部变量,则可能在循环结束时破坏它.要合法销毁,必须detach编辑,join移动或移动线程对象.如果你的线程是简单的"发射后不管",你永远不会有后来与他们进行同步(即使是干净关闭),则只需调用std::thread::detach创建后的线程上.否则,您可以将其放入std::vector<std::thread>,以便您可以找到它并在以后加入它.

  • @Drop我不确定这是个好主意.你不希望析构函数意外地分离一个线程,你当然不想阻止`join`. (2认同)

Ric*_*ges 5

它看起来好像你不想管理线程的生命周期(这几乎总是一个错误).

如果你真的想这样做,那就是这样做的:

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
}
Run Code Online (Sandbox Code Playgroud)

  • 简短的回答是无限线程的产生不是一个可扩展的解决方案.最终,您需要将逻辑转换为具有线程池的异步模型,或者将连接限制为某个上限. (3认同)
  • "这几乎总是一个错误" - 为什么?它是一个accept()线程,它可能需要在进程的生命周期内运行.进程生命周期线程远非异常. (2认同)