如何处理永远不会执行的代码
how to handle code that never executes
我有一些看起来像这样的代码,我不确定如何处理永远不会执行的部分,因为这段代码的一部分在等待连接时以无限循环运行,当我终止程序时,它仅从那里退出。
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;
}
如果您的代码将被其他人使用或者您自己只是想让它更干净,您可以并且可能应该添加一个退出处理程序。在您的退出处理程序中,您可以切换使 while()
循环终止的标志。下面的代码对于这个用例将 100% 正常工作,并且可靠且跨平台,但如果你想做更复杂的事情,你应该使用适当的线程安全 OS 特定函数或类似 Boost 或 C++11 的东西
首先声明两个全局变量,使它们成为易变的,这样编译器总是会强制我们读取或写入它的实际内存值。如果您不将其声明为 volatile,那么编译器可能会将其值放入寄存器中,这将使它不起作用。使用 volatile 设置,它会在每个循环中读取内存位置并正常工作,即使有多个线程也是如此。
volatile bool bRunning=true;
volatile bool bFinished=false;
而不是你的 while(1) {}
循环,把它改成这个
while(bRunning)
{
dostuff
}
bFinished=true;
在您的退出处理程序中只需设置 bRunning=false;
void ExitHandler()
{
bRunning=false;
while(bFinished==false) { Sleep(1); }
}
您没有指定操作系统,但看起来您是基于 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...
}
而在 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...
}
注意这里需要测试等待bFinished
。如果您不在 Windows 上执行此操作,您的应用可能没有足够的时间关闭,因为退出处理程序由单独的 OS 特定线程调用。在 Linux 上,这不是必需的,您需要退出处理程序才能让主线程继续。
另一件需要注意的事情是默认情况下 Windows 只给你大约 5 秒的时间让你在它终止你之前关闭。这在很多情况下是不幸的,如果需要更多时间,您将需要更改注册表设置(坏主意)或实施可以更好地挂钩这些东西的服务。对于您的简单情况,它会很好。
对于这些事情,OS 将负责在关机时正确释放资源。然而,更一般地说,您仍然需要确保分配的资源在程序执行期间不会堆积,即使它们被 OS 自动回收,因为这样的资源泄漏仍然会影响您的行为和性能程序。
现在,关于手头的资源,没有理由不像对待 C++ 中的所有资源一样对待它们。公认的规则是将它们绑定到一个对象,该对象将在它们的析构函数中释放它们,另请参见 RAII 习惯用法。这样,即使在稍后的某个阶段有人添加了 break
语句,代码仍会正常运行。
顺便说一句:我在这里看到的更严重的问题是通常缺乏适当的错误处理。
我有一些看起来像这样的代码,我不确定如何处理永远不会执行的部分,因为这段代码的一部分在等待连接时以无限循环运行,当我终止程序时,它仅从那里退出。
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;
}
如果您的代码将被其他人使用或者您自己只是想让它更干净,您可以并且可能应该添加一个退出处理程序。在您的退出处理程序中,您可以切换使 while()
循环终止的标志。下面的代码对于这个用例将 100% 正常工作,并且可靠且跨平台,但如果你想做更复杂的事情,你应该使用适当的线程安全 OS 特定函数或类似 Boost 或 C++11 的东西
首先声明两个全局变量,使它们成为易变的,这样编译器总是会强制我们读取或写入它的实际内存值。如果您不将其声明为 volatile,那么编译器可能会将其值放入寄存器中,这将使它不起作用。使用 volatile 设置,它会在每个循环中读取内存位置并正常工作,即使有多个线程也是如此。
volatile bool bRunning=true;
volatile bool bFinished=false;
而不是你的 while(1) {}
循环,把它改成这个
while(bRunning)
{
dostuff
}
bFinished=true;
在您的退出处理程序中只需设置 bRunning=false;
void ExitHandler()
{
bRunning=false;
while(bFinished==false) { Sleep(1); }
}
您没有指定操作系统,但看起来您是基于 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...
}
而在 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...
}
注意这里需要测试等待bFinished
。如果您不在 Windows 上执行此操作,您的应用可能没有足够的时间关闭,因为退出处理程序由单独的 OS 特定线程调用。在 Linux 上,这不是必需的,您需要退出处理程序才能让主线程继续。
另一件需要注意的事情是默认情况下 Windows 只给你大约 5 秒的时间让你在它终止你之前关闭。这在很多情况下是不幸的,如果需要更多时间,您将需要更改注册表设置(坏主意)或实施可以更好地挂钩这些东西的服务。对于您的简单情况,它会很好。
对于这些事情,OS 将负责在关机时正确释放资源。然而,更一般地说,您仍然需要确保分配的资源在程序执行期间不会堆积,即使它们被 OS 自动回收,因为这样的资源泄漏仍然会影响您的行为和性能程序。
现在,关于手头的资源,没有理由不像对待 C++ 中的所有资源一样对待它们。公认的规则是将它们绑定到一个对象,该对象将在它们的析构函数中释放它们,另请参见 RAII 习惯用法。这样,即使在稍后的某个阶段有人添加了 break
语句,代码仍会正常运行。
顺便说一句:我在这里看到的更严重的问题是通常缺乏适当的错误处理。