在服务器应用程序的情况下,是截断线被视为良好,中性或设计差的线程

In the case of a server application, is detatching threads considered good, neutral, or poor design

本文关键字:线程 情况下 应用程序 服务器 断线      更新时间:2023-10-16

我最近使用Winsock使用在线指南编写了一个简单的TCP服务器。然后,我尝试在没有指南的帮助下进行多线程。经过一段时间的挣扎,我最终取得了成功,但只有脱离线程。

我有一个无限的环路,每当accept()返回SOCKET时,它会创建Handler,并在accept()SOCKET结果中调用handle()。这是handle()函数,它从accept()调用中获取套接字,并创建调用processData的线程:

void Handler::handle(SOCKET socket)
{
    std::thread handlerThread([socket]{
        processData(socket);
    });
}

这是实际的processData函数,它是Handler中的静态函数:

void Handler::processData(SOCKET socket)
{
    try
    {
        const int buffLength = 512;
        char recvBuff[buffLength];
        int recvResult = recv(socket, recvBuff, buffLength, 0);
        if(recvResult > 0)
        {
            std::cout << recvBuff << std::endl;
        }
        closesocket(socket);
    }
    catch(std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
}

此代码将在recv()上使用代码R6010的abort()以某种方式逃脱了try-catch。直到我将handle功能更改为

void Handler::handle(SOCKET socket)
{
    std::thread handlerThread([socket]{
        processData(socket);
    });
    handlerThread.detach();
}

它能够通过recv()调用。

如果有人可以解释为什么分离线程会对recv()产生影响,并且知道如果有更期望的设计模式,您不必脱离工作人员线程,如果您与我分享,我将非常感谢。

如果这太具体了,则可以在上发表您的意见。

来自规格:

30.3.1.3线程驱动器[thread.thread.destr] 〜thread(); 如果Joinable(),请调用std :: terminate()。否则,没有效果。

在您的第一种情况下,当 handle返回时,当您的线程对象在堆栈上时,destructor被调用。由于您的底部线程仍在运行并在recv功能中被阻塞std::terminate()。最终导致abort()调用。
当您分离线程时,您可以破坏std::thread对象,因为它不再可加入。

我个人试图避免脱离线程。因此,在您的情况下,我更喜欢线程池,或者您通过将其存储在矢量中来跟踪线程对象。

正如@mkaes已经回答的那样,只要线程不脱离,它就在线程对象的上下文中起作用,因此当对象被破坏时会停止。

就线程而言,我要么使用临时线程或静态线程。通常,在服务器上,不应停止静态线程,因此可以分离。对于临时线程,您要么想要一些结果,因此您必须在某个时候加入它们,或者您不这样做,因此可以分离。

线程的问题通常可以优雅地结束您的应用程序。如果您拥有独立的线程,这将更加困难,因为即使您发出信号要停止,您也需要额外的机制来找出所有线程是否已经结束(即使那样,您也永远不会100%确定),所以这似乎是主要的避免脱离线程的原因。