如何在使用阻止调用时退出程序

时间:2013-04-11 00:05:26

标签: multithreading sockets destructor exit blocking

我需要做一个项目,其中应用程序监视传入连接并应用xml文档中定义的一些规则。规则是过滤(阻止或允许)连接或重定向某个端口上的流量。为了做到这一点,我使用了诸如accept和recv(来自Winsock)之类的函数。所有这些函数都用在不同的线程上。我想知道,在退出之前我应该​​如何清理程序,因为所有阻塞调用都已完成。通常我会等到这个人通过X按钮退出控制台或等待用户在主线程中输入某个字符。问题是我不确定如果应用程序在仍有活动线程的情况下退出/如果仍然分配内存/如果正在使用套接字,会发生什么。所有的析构函都被称为? h andles和socket是否正确关闭?或者我是否需要以某种方式自己做?

由于

2 个答案:

答案 0 :(得分:1)

总的来说,我会说不。除非你绝对被迫,否则不要尝试显式清理套接字,fd,句柄,线程等资源。

确切的行为取决于操作系统以及如何终止您的应用。

当进程终止时,所有常见的桌面操作系统都将释放操作系统分配给进程的资源。这包括套接字,文件描述符,内存。

在Windows / Linux上,如果从C / C ++ main()返回而没有任何明确的清理,则静态dtors将被crt代码调用。不运行非主线程中动态分配对象的Dtors。

用其他语言编写的可执行文件可能表现不同。

如果不是从main()返回,而是直接调用'ProcessExit()'API,静态析构函数将不会被调用,因为操作系统没有dtors的概念 - 它不知道或感兴趣的是什么语言用于生成可执行文件。

在任何一种情况下,都会调用操作系统来终止您的进程。操作系统通过首先更改未运行的所有进程线程的状态来执行此操作(简单的“Dummies”版本:),以便它们永远不会再次运行。然后停止在其他核心上运行的线程。然后关闭fd,套接字等操作系统资源,然后释放,然后释放所有进程内存,然后释放操作系统内核进程/线程对象,然后您的进程不再存在。

如果你绝对需要一些或全部C ++ /当一些线程需要停止应用程序时调用的任何dtors,你将必须明确地指示其他线程停止以便运行dtors。我倾向于使用全局可访问的'CloseRequested'布尔值,相关的阻塞调用在返回后立即检查。仍存在说服阻止调用返回的问题。

某些阻塞调用可以编码为等待多个信号,因此允许调用通过简单事件/ sema / condvar /任何信号返回。

有些调用,比如recv(),accept(),可以通过关闭他们正在等待的fd / socket来提前返回。

可以通过'人工'来满足他们的等​​待条件来进行一些调用 - 例如。创建临时文件只是为了使文件夹监视器调用返回,以便可以检查'CloseRequested'布尔值。

如果阻塞调用非常顽固,无法说服它返回,你可以重新设计你的应用程序,以便在dtors中发布的任何关键资源都可以被另一个线程释放 - 也许在另一个线程中创建线程并将其传递给阻塞ctor参数的线程,类似于此。

注意:如上所列,线程关闭代码提供的附加代码不会增加应用程序的正常功能。您应该将显式线程关闭限制为那些保存绝对必须由显式用户代码释放的资源的线程 - 比如数据库连接。如果操作系统可以释放资源,则应该允许它这样做。操作系统非常擅长在释放所使用的资源之前停止所有进程线程,用户代码不是。

答案 1 :(得分:0)

尽可能使用带有超时值的阻塞调用,并使线程循环。这使您可以检查关闭条件并正常退出线程。当过程退出时,系统通常会清理手柄。优雅地关闭套接字是礼貌的,但不是绝对强制的。不这样做的缺点是内核可能需要一段时间来清理独占资源。例如,如果你只是杀死一个等待accept()的线程,然后重新启动你的应用程序,那么在内核清理旧套接字之前,它将无法在同一端口上成功接受()。