如何处理从不执行的代码

Abh*_*yal 10 c++ linux networking loops infinite-loop

我有一些代码,看起来像这样,我不知道该如何处理,因为这代码的一部分,在无限循环运行,同时等待连接,当我终止程序,它从那里只有退出,这将永远不会得到执行的部分.

main(){

// do some stuff....

    while(1) {
        int newFD =
            accept(sockFD, (struct sockaddr *)&client_addr, &client_addr_size);
        if(newFD == -1) {
            std::cerr << "Error while Accepting on socket" << std::endl;
            continue;
        }

        if(!fork()) {

            close(sockFD); // close child's sockfd - not needed here

            // lalala do stuff send message here                

            close(newFD);  // finally close its newFD - message sent, no use 
            return 0;
        }
        close(newFD);  // close parent's newFD - no use here
    }

    // now execution never reaches here
    close(sockFD);      // so how to handle this?
    freeaddrinfo(res);  // and this?

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Ryl*_*den 15

如果您的代码要由其他人使用,或者您自己只是希望它更清洁,您可以,并且可能应该添加退出处理程序.在退出处理程序中,您可以切换使while()循环终止的标志.以下代码对于此用例将100%正常工作,并且是可靠且跨平台的,但如果您想要执行更复杂的操作,则应使用正确的线程安全操作系统特定功能或类似Boost或C++ 11

首先声明两个全局变量,使它们变为volatile,这样编译器总是会强制我们读取或写入它的实际内存值.如果我们没有声明它是volatile,那么编译器可能会将其值放在一个寄存器中,这会使它不起作用.使用volatile set,它将读取每个循环上的内存位置并正常工作,即使有多个线程也是如此.

volatile bool bRunning=true;
volatile bool bFinished=false;
Run Code Online (Sandbox Code Playgroud)

而不是你的while(1) {}循环,将其更改为此

while(bRunning)
{
    dostuff
}
bFinished=true;
Run Code Online (Sandbox Code Playgroud)

在你的退出处理程序中设置 bRunning=false;

void ExitHandler()
{
    bRunning=false;
    while(bFinished==false) { Sleep(1); }
}
Run Code Online (Sandbox Code Playgroud)

您没有指定操作系统,但看起来您是基于Linux的,要在Linux上设置您需要的处理程序.

void ExitHandler(int s)
{
    bRunning=false;
}

int main()
{
    struct sigaction sigIntHandler;
    sigIntHandler.sa_handler = ExitHandler;
    sigemptyset(&sigIntHandler.sa_mask);
    sigIntHandler.sa_flags = 0;
    sigaction(SIGINT, &sigIntHandler, NULL);
    while(bRunning)
    {
        dostuff
    }
    ...error_handling...
}
Run Code Online (Sandbox Code Playgroud)

在Windows上,当您是一个控制台应用程序时,其如下所示.

BOOL WINAPI ConsoleHandler(DWORD CEvent)
{
    switch (CEvent)
    {
        case CTRL_C_EVENT:
        case CTRL_BREAK_EVENT:
        case CTRL_CLOSE_EVENT:
        case CTRL_LOGOFF_EVENT:
        case CTRL_SHUTDOWN_EVENT:
            bRunning = false;
            while (bFinished == false) Sleep(1);
            break;
    }
    return TRUE;
}

int main()
{
    SetConsoleCtrlHandler(ConsoleHandler, TRUE);
    while(bRunning()
    {
        dostuff
    }
    ...error_handling...
}
Run Code Online (Sandbox Code Playgroud)

注意需要在bFinished这里测试并等待.如果您不在Windows上执行此操作,则您的应用程序可能没有足够的时间来关闭,因为退出处理程序由单独的OS特定线程调用.在Linux上,这不是必需的,您需要退出处理程序以使主线程继续.

另外需要注意的是,默认情况下,Windows只会在你终止之前关闭约5秒钟.在许多情况下这是不幸的,如果需要更多时间,您将需要更改注册表设置(错误的想法)或实现一个更好地挂钩这类事情的服务.对于你的简单情况,它会没事的.

  • 呵呵.我刚刚添加了Windows代码,因为它与其他可能会搜索相同答案的人相关,而是在Windows上.希望它有用! (4认同)
  • 不要`(PHANDLER_ROUTINE)ConsoleHandler`,这只是在惹麻烦.你不应该需要演员.此外,使用挥发性和希望最好也是不好的.相反,使用`Interlocked*`系列函数.最后,是不是在现有线程之一的上下文中执行的control-C处理程序?如果你等待那个线程完全终止那么那将是致命的...... (4认同)

Ulr*_*rdt 10

对于这些事情,操作系统将负责在关机时正确释放资源.但是,更一般地说,您仍需要确保分配的资源在程序执行期间不会堆积,即使它们被操作系统自动回收,因为这样的资源泄漏仍会影响程序的行为和性能.

现在,关于手头的资源,没有理由不像C++中的所有资源那样对待它们.接受的规则是将它们绑定到将在析构函数中释放它们的对象,另请参阅RAII习语.这样,即使在稍后阶段有人添加了一个break语句,代码仍然会正常运行.

BTW:我在这里看到的更严重的问题是缺乏正确的错误处理.

  • 你能评论"错误处理"部分吗?我很乐意根据您的建议改进我的代码,因为我以前从未做过这种工作. (3认同)