Delphi死锁解释/解决方案

2024-01-03

在服务器应用程序上,我们有以下内容: 一个称为 JobManager 的单例类。 另一个类是 Scheduler,它不断检查是否需要向 JobManager 添加任何类型的作业。

当需要这样做时,调度程序会执行以下操作:

TJobManager.Singleton.NewJobItem(parameterlist goes here...);

同时,在客户端应用程序上,用户执行一些操作来生成对服务器的调用。在内部,服务器向自身发送一条消息,监听该消息的类之一是 JobManager。 JobManager 处理该消息,并知道是时候将新作业添加到列表中,调用它自己的方法:

NewJobItem(parameter list...);

在 NewJobItem 方法中,我有这样的内容:

  CS.Acquire;
  try
    DoSomething;
    CallAMethodWithAnotherCriticalSessionInternally;
  finally
    CS.Release;
  end;

恰好系统此时陷入死锁(CS.Acquire)。 客户端和服务器应用程序之间的通信是通过 Indy 10 进行的。 我认为,触发向 JobManager 发送消息的服务器应用程序方法的 RPC 调用正在 Indy 线程的上下文中运行。

Scheduler有自己的线程在运行,它直接调用JobManager方法。这种情况容易陷入僵局吗? 有人可以帮助我理解为什么这里会发生僵局吗?

我们知道,有时,当客户端执行特定操作时,导致系统锁定,那么我最终可以找到这一点,即从不同的点(调度程序和JobManager 的消息处理程序方法)。

更多信息

我想补充一点(这可能很愚蠢,但无论如何......)在 DoSomething 中还有另一个

  CS.Acquire;
  try
    Do other stuff...
  finally
    CS.Release; 
  end;

这个内部 CS.Release 对外部 CS.Acquire 做了什么?如果是这样,这可能是调度程序进入关键部分的点,并且所有锁定和解锁都会变得一团糟。


关于您的系统没有足够的信息能够明确地告诉您 JobManager 和 Scheduler 是否导致死锁,但如果它们都调用相同的 NewJobItem 方法,那么这不应该是问题,因为它们都会获取以相同的顺序锁定。

对于您的问题,您的 NewJobItem CS.acquire 和 DoSomething CS.acquire 是否相互交互:这取决于。如果两个方法中使用的锁对象不同,则这两个调用不应该是独立的。如果是同一个对象,则取决于锁的类型。如果您的锁是可重入锁(例如,它们允许从同一线程多次调用 acquire 并计算它们已被获取和释放的次数),那么这应该不是问题。另一方面,如果您有不支持重入的简单锁定对象,则 DoSomething CS.release 可以释放该线程的锁定,然后 CallAMethodWithAnotherCriticalSessionInternally 将在没有获得的 CS 锁定保护的情况下运行新作业项目。

当有两个或多个线程正在运行并且每个线程都在等待另一个线程完成其当前作业才能继续其自身时,就会发生死锁。

例如:

Thread 1 executes:

lock_a.acquire()
lock_b.acquire()
lock_b.release()
lock_a.release()


Thread 2 executes:

lock_b.acquire()
lock_a.acquire()
lock_a.release()
lock_b.release()

请注意,线程 2 中的锁以与线程 1 相反的顺序获取。现在,如果线程 1 获取了 lock_a,然后被中断,线程 2 现在运行并获取 lock_b,然后开始等待 lock_a 可用,然后才能继续。然后线程 1 继续运行,它所做的下一件事是尝试获取 lock_b,但它已经被线程 2 占用,因此它等待。最后,我们处于这样一种情况:线程 1 正在等待线程 2 释放 lock_b,线程 2 正在等待线程 1 释放 lock_a。

这是一个僵局。

常见的解决方案有以下几种:

  1. 在所有代码中仅使用一个共享全局锁。这样就不可能有两个线程等待两个锁。这使得您的代码需要等待很长时间才能获得锁。
  2. 只允许您的代码一次持有一把锁。这通常很难控制,因为您可能不知道或控制方法调用的行为。
  3. 只允许您的代码同时获取多个锁,并同时释放它们,并且在已经获取锁的情况下禁止获取新锁。
  4. 确保以相同的全局顺序获取所有锁。这是一种更常见的技术。

对于解决方案 4,您需要仔细编程并始终确保以相同的顺序获取锁/临界区。为了帮助调试,您可以对系统中的所有锁放置一个全局顺序(例如,每个锁只有一个唯一的整数),然后如果您尝试获取一个等级低于该锁的等级的锁,则抛出错误当前线程已经获取(例如,如果 new_lock.id

如果您无法放入全局调试辅助工具来帮助查找哪些锁已被无序获取,那么我建议您找到代码中获取任何锁的所有位置,然后打印一条调试消息:当前时间、调用acquire/release的方法、线程id以及正在获取的锁id。对所有发布调用也执行相同的操作。然后运行您的系统,直到出现死锁,并在日志文件中查找哪些线程已按什么顺序获取了哪些锁。然后确定哪个线程以错误的顺序访问其锁并更改它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Delphi死锁解释/解决方案 的相关文章

  • 多线程调试技术

    我想知道是否有人知道多线程应用程序调试技术的一个很好的调查 理想情况下 我正在寻找基于案例的分析 死锁 饥饿 损坏的共享状态 Net 特定的或通用的 我不知道有哪篇文章或书籍可以满足您的需求 因此这是我从 12 年 Windows 多线程调
  • BufferBlock 连续

    我想使用以下方式实现消费者 生产者模式BufferBlock
  • Delphi XE5 FireDAC 错误:无法加载供应商库 [libmysql.dll 或 libmysqld.dll]

    我在 Windows 7 64 位上使用 Delphi XE5 只是尝试 FireDAC 组件 我正在使用一个 TFDConnection 组件连接到本地 MySQL 数据库 v5 6 15 我已经将 libmysql dll 32位 v5
  • DBX 错误:驱动程序无法正确初始化

    我在跑步德尔福XE3 终极版 MySQL 数据库 这是我点击时收到的错误Test Connection 作为回应 我在 xampp 目录中找到了 libmysql 库 并将其复制到我的 System32 目录中 但这是行不通的 此消息指的是
  • 将带有 **kwargs 错误的值线程化并传递给 TypeError

    我对 Python 还很陌生 并且正在通过这篇文章研究如何使用线程来处理某些代码 Python 使用线程或队列迭代调用函数的 for 循环 https stackoverflow com questions 12868956 python
  • 在该对象调用的事件期间销毁该对象

    我有一个按钮 它的 OnClick 事件调用一个销毁按钮的过程 但随后 线程 想要返回到 OnClick 事件 并且我遇到了访问冲突 我完全被难住了 您需要在按钮的所有代码执行完毕后销毁该按钮 执行此操作的标准方法是将用户定义的消息发布到表
  • 指针^ 与 s[1]

    在读取数据的函数中 数据含义只字符串 从磁盘 我应该更喜欢哪个 哪个更好 A DiskStream Read Pointer s Count or B DiskStream Read s 1 Count Note 我知道两者都有相同的结果
  • C# 为所有对象订阅相同的事件处理程序是线程安全的吗

    我的项目中有一种情况 我连接到多个服务器并监听事件 每当从服务器接收到事件时 Handler 就应该将该事件添加到公共队列中进行处理 所有连接都应将接收到的事件添加到队列中 foreach var item in collection Co
  • 在 tlistbox 中绘制缩略图

    在 DelphiXE 中 我使用 tFileOpenDialog 选择一个文件夹 然后在 tListBox 中列出该文件夹中的所有 jpg 文件 我允许将列表项拖放到列表中进行自定义排序 以便稍后按顺序显示它们 我希望能够在文件名旁边绘制图
  • 获取Windows下新线程/删除线程的通知

    创建 DLL 时 您可以在 DllMain 函数 DLL THREAD ATTACH DLL THREAD DETACH 中获取有关新线程 退出线程的通知 有没有办法在 非托管 可执行文件中从 Windows 获取这些或等效通知 是的 在您
  • 异步调用的任务限制?

    我有一个同步工作的 NET 4 5 WCF 客户端 我正在更新它以使用新的异步 等待功能来进行多个同时服务器调用以同时获取数据块 在结束之前 我担心同时运行的所有线程将使服务器饱和 更不用说明年升级到该角色时会终止我的 Azure 辅助角色
  • 从另一个线程调用线程中的方法,python

    如何实现线程之间的通信 我有一个线程在其中执行一些操作 然后我需要从位于主程序线程中的对象调用一个方法 并且该方法应该在主进程中执行 class Foo def help self pass class MyThread threading
  • Qt:关闭期间线程仍在运行时 qthread 被销毁

    我有一堂课 class centralDataPool public QObject Q OBJECT public centralDataPool QObject parent 0 centralDataPool commMonitor
  • 使用 Inno Setup 中格式化(部分粗体)的文本制作安装程序?

    有人看过 GOG com 游戏安装程序吗 如何制作像这样的欢迎文本字符串 包括单个标题中的路径和需要大小 其中部分内容加粗 以下是修改安装路径后如何更改字符串换行的示例 您可以使用TRichEditViewer http www jrsof
  • 我的 Delphi 11.1 调试器在 x64 项目上突然变得非常缓慢;大约一周前还可以。有什么想法吗?

    更新 拔掉网络 电缆和wifi 会导致 几乎 恢复正常的调试速度 已尝试禁用防火墙没有任何变化 但没有网络恢复正常服务 更新 2 所有 Windows x64 版本都存在缓慢问题 而不仅仅是单个大型项目 如果我构建并调试 32 位 Wind
  • 检测您何时进入/退出 Xamarin.iOS 中的主线程

    Xamarin MonoTouch 有没有办法检测主线程中是否正在调用代码 我正在寻找类似于Java的东西EventQueue isEventDispatchThread 我发现 Swing 编程很方便assert时不时 或有时assert
  • Java 线程 JavaDoc

    我编写了一个只能在特定线程上调用的方法 是否应该将标准注释或注释添加到方法的 javadoc 中来表示这一点 不知道有任何这样的标准注释 Java 并发实践 http www javaconcurrencyinpractice com 在第
  • 为什么我的代码在编译用于分析 (-pg) 时在多线程下运行比在单线程下运行慢?

    我正在写一个光线追踪器 最近 我在程序中添加了线程 以利用 i5 四核上的附加内核 奇怪的是 应用程序的调试版本现在运行速度变慢 但优化后的构建运行速度比添加线程之前更快 我将 g pg 标志传递给 gcc 以进行调试构建 并将 O3 标志
  • iPhone SDK - 在后台线程中运行重复进程

    我有一个iPhone我想在其中每隔一段时间在后台执行一个方法的应用程序1第二 所以在我的主线程中 我有以下代码UIViewController viewDidLoad NSTimer timerWithTimeInterval 1 0 ta
  • 线程、进程和 Application.Exit()

    我的应用程序由主消息循环 GUI 和线程 Task Factory 组成 在线程中我调用一些第三方应用程序var p new Process 但是当我调用Application Exit 在消息循环中 我可以看到在线程中启动的进程仍在内存中

随机推荐

  • h:commandLink 的 oncomplete 属性未调用

    我们正在从 JSF 1 2 迁移到 JSF 2 2 6 以及 RichFaces 4 5 2 面临的问题oncomplete没有被叫到 期间的JS函数onclick被调用 但是 JS 在oncomplete没有被调用 这是如何引起的以及如何
  • 后端基于休息的服务

    我们建立了一个超过 3000 万用户的在线社区 该社区的后端有 RESTful 服务 前端也使用这些服务 我担心的是 与Java的二进制序列化协议 取决于语言 相比 使用REST作为内部数据传输协议是否可以 或者它会显着降低性能 可以使用哪
  • WordPress 网站显示内联 css 代码

    我正在一个网站上工作http kaniamea com turtle http kaniamea com turtle 如果您查看源代码 您将看到以下内容 这是内联代码 它随主题一起提供 有没有办法在子文件夹中的单独样式表中组织此代码 还有
  • 数据库连接自动重新连接

    我在 Tomcat 中有一个 DBCP 连接池 问题是 当连接短暂丢失时 应用程序就会中断 因为 DBCP 不会在稍后有连接时尝试再次重新连接 我可以让 DBCP 自动重新连接吗 有两种方法可以 解决 这个问题 尽管两者都存在一些问题 您可
  • 从 SQL Server 中的行创建列

    我有一个 SQL 查询 它提供以下格式的数据 Total Hours Year 100 00 2012 200 00 2012 300 00 2012 75 00 2011 150 00 2011 50 00 2010 125 00 201
  • MPMediaItemArtwork 返回错误尺寸的图稿

    我发现 MPMediaItemArtwork 存在一个一致的问题 即它返回的图稿尺寸与我请求的尺寸不同 我正在使用的代码如下 MPMediaItem representativeItem self representativeItems o
  • Android TabHost.addTab -> 空指针异常

    这是我的代码 public class Main extends Activity Override public void onCreate Bundle savedInstanceState TabHost tabHost new Ta
  • 将 localStorage 值加一

    我正在开发我们的应用程序的尝试登录功能 他们失败了三次 就把他们彻底踢出了局 为了记录他们尝试的次数 我认为我会使用 localStorage 因为我可以轻松地操作它 但是 当他们无法验证自己的身份时 我无法增加该值 在顶部 我设置 loc
  • 如何从 Java 8 lambda/流内部抛出已检查的异常?

    如何从 Java 8 lambda 内部抛出已检查的异常 例如在流中使用 换句话说 我想让代码像这样编译 public List
  • NSOperationQueue 在 IOS 中崩溃

    我有一个项目 它使用以下方式在后台下载图像NSOperationQueue 到目前为止 它可以在 iOS 4 3 的设备上运行 但是 如果我使用基础 sdk 4 3 或 5 构建应用程序并在使用 IOS5 的设备上运行该应用程序 则该应用程
  • SparkSQL 和 Java 中的 DataFrame 上的爆炸

    有没有简单的方法如何使用explodeSpark SQL 中的数组列DataFrame 在Scala中相对简单 但在Java中这个功能似乎不可用 如javadoc中提到的 一个选项是使用SQLContext sql and explode查
  • Rails Arel 通过连接表上的 where 条件进行连接

    我正在尝试将以下 Rails where 子句转换为使用 Arel 主要是为了利用orArel 提供的方法 后模型 class Post belongs to user end 用户模型 class User has many posts
  • Delphi 7 - 如何使用标题从列表视图中删除项目

    我正在尝试删除基于标题的列表视图项目 但我找不到解决方案 删除项目的唯一方法是使用索引 listview1 Items Delete 0 谁能帮我通过标题删除项目 您可以使用类似的东西 它尝试找到ListItem与标题Item 2 如果找到
  • Python:如何根据网络节点的度数为其着色?

    我有一个无标度网络10000节点 但边缘的纹理和节点的数量使其过于复杂而难以理解 我希望能够直观地找到连接程度最高的节点 我如何根据节点的 k 度对节点进行着色 具体来说 我想根据预先指定的范围为它们着色 例如 绿色如果1
  • Windows 上的 System.err 在哪里?

    我有一个基于 Java GUI 的应用程序 它将一些诊断消息写入 System out 和 System err 在 Windows 上运行时这些消息输出在哪里 例如 在 Mac OS X 上 它们被打印到系统控制台日志中 Edit 我应该
  • pyqt QtGraphicsView 未在循环内更新

    我有一个基于 PyQt 构建的 GUI 程序 GUI 有一个 QtGraphicsView 小部件 其中有一个 GraphicsScene 其中有一个要显示和更新的 Pixmap 项目 例如 我使用以下行来执行此操作 view scene
  • 使用 scanf 的返回值验证输入不起作用

    我正在做一个井字棋期末项目 我要求用户打印他想要填写的框号 然后我使用整数err来获取返回值scanf 在这种情况下 scanf 应该返回它已读取的整数数量 而我要求读取一个整数 因此只要 err 1 它就应该进入 while 循环 然而
  • C# 开发工作的项目结构 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 What directory solution project structure do you find to be the most man
  • 如何在 Vapor 3 中将字典的元素分配给 JSON 对象?

    在 Vapor 1 5 中 我曾经将现有字典的元素分配给 JSON 对象 如下所示 我该如何做这个 Vapor 3 func makeCustomJSON jsonFromReading JSON clientData DataFromCl
  • Delphi死锁解释/解决方案

    在服务器应用程序上 我们有以下内容 一个称为 JobManager 的单例类 另一个类是 Scheduler 它不断检查是否需要向 JobManager 添加任何类型的作业 当需要这样做时 调度程序会执行以下操作 TJobManager S