当前位置: 首页 > 面试题库 >

取消已锁定互斥锁的线程不会解锁互斥锁

谷德本
2023-03-14
问题内容

帮助客户解决他们遇到的问题。我更多地是sysadmin /
DBA的人,所以我在努力帮助他们。他们说这是内核/环境中的错误,在我坚持要在他们的代码中或寻求供应商对OS的支持之前,我试图证明或证明这一点。

发生在Red Hat和Oracle Enterprise Linux 5.7(和5.8)上,应用程序用C ++编写

他们遇到的问题是主线程启动一个单独的线程来执行可能长时间运行的TCP
connect()[客户端连接到服务器]。如果“长时间运行”方面花费的时间太长,它们将取消线程并启动另一个线程

这样做是因为我们不知道服务器程序的状态:

  • 服务器程序启动并运行->立即接受连接
  • 服务器程序未运行,机器和网络正常->连接立即失败,错误为“连接被拒绝”
  • 机器或网络崩溃或掉线->连接需要很长时间才能失败,并显示错误“无法路由到主机”

问题在于,取消已锁定互斥锁的线程(设置了清除处理程序以解锁互斥锁)有时无法解锁互斥锁。

这样一来,主线程便无法锁定互斥锁。

详细的环境信息:

  • glibc-2.5-65
  • glibc-2.5-65
  • libcap-1.10-26
  • 内核调试2.6.18-274.el5
  • glibc-headers-2.5-65
  • glibc-common-2.5-65
  • libcap-1.10-26
  • 内核文档2.6.18-274.el5
  • 内核-2.6.18-274.el5
  • kernel-headers-2.6.18-274.el5
  • glibc-devel-2.5-65

使用以下代码构建代码:c ++ -g3 tst2.C -lpthread -o tst2

任何建议和指导都将不胜感激


问题答案:

正确的是,已取消线程不会解锁它们所持有的互斥锁,您需要手动安排该操作,这很棘手,因为您需要非常小心地在每个可能的取消点周围使用正确的清除处理程序。假设您pthread_cancel用于取消线程并设置清除处理程序pthread_cleanup_push以解锁互斥锁,则可以尝试以下两种替代方法,它们可能更容易正确使用,因此可能更可靠。

使用RAII解锁互斥锁
更可靠。在GNU / Linux
pthread_cancel上,使用type的特殊异常来实现__cxxabi::__forced_unwind,因此,取消线程时,将引发异常并取消堆栈堆栈。如果一个互斥锁被RAII类型锁定,那么如果堆栈被__forced_unwind异常取消,则可以保证其析构函数运行。
Boost Thread提供了一个可移植的C
++库,该库包装了Pthreads,并且使用起来更加容易。它提供了RAII类型boost::mutex和其他有用的抽象。Boost
Thread还提供了自己的“线程中断”机制,该机制类似于Pthread取消,但不相同,并且提供了Pthread取消点(例如connect)不是Boost
Thread中断点,这对某些应用程序可能会有帮助。但是,对于您的客户而言,由于取消的目的是中断connect调用,因此他们可能确实希望坚持使用Pthread取消。GNU
/ Linux(非便携式)实现取消的方式是一种例外,这意味着它将与配合使用boost::mutex

在用C 编写时,确实没有任何借口显式锁定和解锁互斥锁。恕我直言,C 最重要和最有用的 功能是析构函数,它是自动释放互斥锁等资源的理想选择。

另一种选择是使用一个强大的互斥体,它是通过调用创建pthread_mutexattr_setrobust一个pthread_mutexattr_t初始化互斥之前。如果线程在持有健壮的互斥锁时死亡,内核将对其进行记录,以便下一个试图锁定互斥锁的线程获得特殊的错误代码EOWNERDEAD。如果可能,新线程可以使该线程保护的数据再次保持一致,并获得互斥锁的所有权。与仅使用RAII类型锁定和解锁互斥锁相比,要正确使用它要困难得多。

完全不同的方法是确定在调用时是否真的需要按住互斥锁connect。在慢速操作期间保持互斥不是一个好主意。connect如果成功锁定了互斥锁并更新了互斥锁正在保护的任何共享数据,那么您不能打电话吗?

我的首选是同时使用Boost Thread和避免长时间保持互斥。



 类似资料:
  • 问题内容: 是多线程/进程编程的新手。所以这是我需要澄清的。 处理代码 使用上述伪代码,如果互斥锁未解锁,进程B是否可以访问? 如何从进程B正确访问sharedResource? 有没有清晰的可视化图表说明互斥体,线程和进程之间的关系? 问题答案: 您需要做的是调用pthread_mutex_lock来保护互斥锁,如下所示: 一旦执行此操作,在您在该线程中进行调用之前,不会再进行任何其他调用。因此

  • Go语言包中的 sync 包提供了两种锁类型:sync.Mutex 和 sync.RWMutex。 Mutex 是最简单的一种锁类型,同时也比较暴力,当一个 goroutine 获得了 Mutex 后,其他 goroutine 就只能乖乖等到这个 goroutine 释放该 Mutex。 RWMutex 相对友好些,是经典的单写多读模型。在读锁占用的情况下,会阻止写,但不阻止读,也就是多个 gor

  • Introduction This is the fourth part of the chapter which describes synchronization primitives in the Linux kernel and in the previous parts we finished to consider different types spinlocks and semap

  • 本文向大家介绍互斥锁死锁,包括了互斥锁死锁的使用技巧和注意事项,需要的朋友参考一下 死锁可以在使用互斥锁的多线程Pthread程序中发生。让我们看看它如何发生。未锁定的互斥锁由pthread_mutex_init()函数初始化。 使用pthread_mutex_lock()和pthread_mutex_unlock()获取并释放互斥锁。如果线程尝试获取锁定的互斥锁,则对pthread_mutex_

  • 我想为strerror\u r调用创建线程本地缓冲区,并编写自己的线程安全字符*my\u strerror(int),它将使用线程本地缓冲区并调用strerror\r。 当阅读R. Stevens在Unix环境高级编程中关于pthread_getspecific()的例子时,我觉得差异-为什么在下面的例子中使用互斥锁? 书中的例子:

  • 本文向大家介绍Python Threading 线程/互斥锁/死锁/GIL锁,包括了Python Threading 线程/互斥锁/死锁/GIL锁的使用技巧和注意事项,需要的朋友参考一下 导入线程包 import threading 准备函数线程,传参数 t1 = threading.Thread(target=func,args=(args,)) 类继承线程,创建线程对象 线程共享全面变量,但在