2008-10-16 62 views
7

我有一个C++ Win32应用程序,当用户想要关闭应用程序时,有一些线程可能正在忙于执行IO(HTTP调用等)。目前,我打得很好,并等待所有的线程结束,然后从main返回。有时,这需要比我想要的更长的时间,事实上,当我可以退出时,让用户等待似乎毫无意义。但是,如果我只是继续并从main返回,那么在析构函数开始被调用的同时还有线程正在使用这些对象时,我很可能会崩溃。如何保证我的win32应用程序快速关闭?

所以,认识到在美德的理想,柏拉图式的世界,最好的事情是等待所有线程完全退出,然后关机,什么是下一个最好的现实世界的解决方案?简单地让线程更快地退出可能不是一种选择。我们的目标是尽快让程序停止,以便例如可以在其上安装新版本。我正在做的唯一一个磁盘IO是在一个事务性的数据库中,所以我并不担心拉上那个插件。

回答

2

最好的方式,做你的工作的应用程序运行时,什么事都不做(或接近)在关机(工程启动过)。如果你坚持这种模式,那么当关闭请求到来时,你可以立即拆除线程(而不是“很好”),而不用担心仍然需要完成的工作。

在你的具体情况,你可能需要等待IO完成(写入,至少)如果你正在做地方工作在那里。 HTTP请求等,你可能只是放弃/关闭彻底(再次,除非你正在写东西)。但是,如果在这种关机和等待的过程中,您正在编写这种情况,那么您可能希望通知用户这一点,而不是让您的流程在包装时看起来挂起。

-5

指示用户拔下电脑。因此,你必须放弃异步活动。还是那个HWIND?我永远不会记得在C++中。当然,你可以走中间路线,并快速记下文本文件或注册表键,哪些操作被放弃,以便下次程序运行时,它可以自动重新执行该操作,或询问用户是否想要这样做。根据放弃异步操作时丢失的数据,您可能无法做到这一点。如果您与用户进行交互,您可能需要考虑一个对话或一些UI交互,以解释为什么需要这么长时间。

就个人而言,我更喜欢指令,用户只拔掉电脑。 :)

+0

给出一个有趣的答案,将其改写成深渊,它看起来像...人们没有幽默感...... – tloach 2008-10-16 19:45:45

+0

是的,我受伤了。也许他们的堆栈溢出了。 – 2008-10-16 20:35:24

+1

DIGG或Slashdot是那个-----> – jim 2008-10-17 12:11:41

0

如果你想乱七八糟拔出插头,出口(0)会做的伎俩。

2

我建议让你的GUI和工作在不同的线程上完成。当用户请求关闭时,立即关闭GUI,看起来应用程序已关闭。允许工作线程在后台优雅地关闭。

7

使用重叠的IO让你在正在处理您的I/O,并可以随时在任何时候停止这些线程的掌握之中;你可以让他们在IOCP上等待,并可以发布一个应用级别的关闭代码,或者你可以等待OVERLAPPED结构中的事件,并等待你的'所有线程,请关闭现在'事件。

总之,避免阻塞你不能取消的呼叫。

如果你不能和你被困在一个阻塞的套接字调用中,那么你总是可以从线程中关闭套接字,这个套接字已经决定了是时候关闭了,并且让线程一直在做IO重试前的'正在关机'事件...

0

我曾经有过类似的问题,尽管在Visual Basic 6中:应用程序的线程将连接到不同的服务器,下载一些数据,执行一些操作循环这些数据,并将结果存储在中央服务器上。

然后,新的要求是线程应该从主窗体停止。我以一种容易但很脏的方式完成了这个任务,通过让线程在N个循环之后停止(大约相当于半秒)来尝试打开具有特定名称的互斥锁。一旦成功,他们立即停止他们正在做的事情并退出,否则继续。

这个互斥体仅仅由主窗体创建,一旦创建它,​​所有的线程都很快关闭自己。缺点是用户需要手动指定它想要再次运行线程 - 另一个按钮“启用线程运行”通过释放互斥量完成了这一操作:D

这个技巧保证可用于互斥操作是原子操作。问题是你不确定一个线程真的关闭 - 处理“openMutex成功”的逻辑失败可能意味着它永远不会结束。你也不知道什么时候/如果所有的线程都关闭了(假设你的代码是正确的,这将需要大致相同的时间来让循环停止并“听”)。

使用VB的多线程“公寓”模型,从线程向主应用程序发送信息有点困难,“发火并忘记”或仅从主应用程序发送到线程。因此,需要这种长时间的切割。使用C++可以自由使用多线程模型,因此这些约束可能不适用于您。

0

无论你做什么,做不是使用TerminateThread,特别是对任何可能在OS HTTP调用中的东西。您可能会破坏IE,直到重新启动。

将您的所有IO更改为异步或非阻塞模式,以便他们可以监视终止事件。

5

我使用了一种基于异常的技术,在很多Win32应用程序中都能很好地工作。

要终止一个线程,我使用QueueUserAPC()将调用排队到引发异常的函数。但是,抛出的异常不是从“Exception”类型派生的,所以只能被我的线程的包装过程捕获。是

这样做的优点如下:

  • 在你的线程不需要特殊的代码,使其“能够停止” - 只要它进入一个alertable等待状态,它将运行APC功能。
  • 所有的析构函数都会在异常运行时被调用,所以你的线程干净地退出。

你需要留意的那些事:

  • 内容。否则catch (...)会吃你的异常。用户代码应始终使用catch(const Exception &e)或类似的!
  • 确保您的I/O和延迟以“可警告”的方式完成。例如,这意味着调用sleepex(N, true)而不是sleep(N)
  • CPU绑定的线程偶尔需要调用sleepex(0,true)来检查终止。

您还可以'保护'您的代码区域,以防止任务在关键部分中终止。

0

如果您需要突然关闭:只需调用ExitProcess即可,只要您从WinMain返回,就会调用它。 Windows本身创建了许多无法清理的工作线程 - 它们被进程关闭终止。

如果您有任何正在执行某种写入的线程 - 显然那些线程需要关闭其资源的机会。但其他任何东西 - 忽略边界检查警告,只是从他们脚下拉下地毯。

0

您可以调用TerminateProcess - 这将立即停止该进程,而不会通知任何人,也不会等待任何内容。

0

*NULL = 0是最快的方法。如果您不想崩溃,请拨打exit()或其相应的win32。