了解 WAIT_ABANDONED 返回值的重要性

了解 WAIT_ABANDONED 返回值的重要性

作者:BlogUpdater |  时间:2023-04-09 |  浏览:383 |  评论已关闭 条评论

互斥锁(Mutex)和其他同步对象之间的重要区别之一是:互斥锁具有所有者。如果拥有互斥锁的线程退出而没有释放互斥锁,则互斥锁会自动释放。

但如果发生这种情况,你就有大麻烦了。

许多人忽略的一件事是同步函数(如 WaitForSingleObject)的 WAIT_ABANDONED 返回值。他们通常将此视为成功的等待,因为这确实意味着已获取对象,但它也告诉你这样一个事实:以前的所有者放弃了互斥锁,并且系统必须代表所有者释放它。

当这种情况发生时,你为什么会遇到大麻烦?

一般情况下,我们创建该互斥锁是为了防止多个线程在共享对象处于不稳定状态时访问该对象。代码进入互斥锁,然后开始操作对象,暂时使其不稳定,但最终重新稳定它,然后释放互斥锁,以便下一个人可以访问该对象。

例如,你可能有下面的代码来管理共享内存中的定位双向链表,如下所示:

没有什么特别令人兴奋的事情发生。都是些基本的东西,对吧?

但是,如果程序在持有互斥锁时崩溃怎么办?(如果你认为程序没有错误,请考虑程序通过网络运行并且网络出现故障的可能性,从而导致页面内异常。或者只是用户转到任务管理器并在此函数运行时终止了程序。)

在这种情况下,操作系统会自动释放互斥锁,使链表处于损坏状态。下一个声明互斥锁的程序将接收WAIT_ABANDONED 作为状态代码。如果忽略该状态代码,则最终会在损坏的链表上运行。根据该链表的使用方式,它可能会导致资源泄漏或系统创建某些内容的意外第二个副本,甚至可能崩溃。一个程序的不幸消亡导致其他程序开始表现奇怪。

然后,问题仍然存在。”那么,如果你得到 WAIT_ABANDONED,你会怎么做?” 答案是:好问题。

如果保留足够的辅助信息以恢复一致状态,则可以尝试修复损坏。你甚至可以将数据结构设计为事务性结构,以便操作数据结构的线程的死亡不会使它们处于损坏状态。或者你可能只是决定,既然对象已经损坏,你应该扔掉所有东西,重新开始,失去正在进行的工作的状态,但至少允许新工作不受阻碍地进行。

或者,你可以简单地选择忽略错误并继续使用损坏的数据结构,希望出现的任何错误都不会导致级联故障。这是大多数人所做的,尽管通常甚至没有意识到他们正在这样做。而且很难调试这种方法导致的崩溃。

课后练习题
为什么我们在链表数据结构中使用索引而不是指针?

总结
一般我在使用 WaitForSingleObject 时,只会使用 WAIT_OBJECT_0 和 WAIT_TIMEOUT 这两个返回值。从今天的文章中,我们应该有所警示:这个函数还可能返回 WAIT_ABANDONED,如果你的代码里没有考虑到这种情况,则当事情发生的时候,程序可能表现的有些异常,且很难定位问题点。
这就是上文所说的大麻烦。

最后
Raymond Chen的《The Old New Thing》是我非常喜欢的博客之一,里面有很多关于Windows的小知识,对于广大Windows平台开发者来说,确实十分有帮助。
本文来自:《Understanding the consequences of WAIT_ABANDONED》

最近我写了个东西
正如你们所知道的,拓扑梅尔智慧办公平台(Topomel Box)是一款绿色软件,主要面向经常使用电脑的朋友。它提供了各种提升办公效率的小功能,同时操作上尽可能地简单方便。
我想:你值得拥有。

评论已关闭。