【问题标题】:DateTime equality and declaration leads to ContextSwitchDeadlockDateTime 相等和声明导致 ContextSwitchDeadlock
【发布时间】:2012-01-27 14:35:19
【问题描述】:

我认为这是一个愚蠢的问题,但发现我无法做到以下几点让我有点奇怪:

EditingItem.FROM = EditingItem.TO = DateTime.Now;   // FROM, TO are DateTime   

在此操作之后,程序有时会挂起,但有时它会按我认为的那样工作。
这是一个例外:

检测到 ContextSwitchDeadlock 消息:CLR 无法 从 COM 上下文 0x478b80 转换到 COM 上下文 0x478dd0 为 60 秒。拥有目标上下文/公寓的线程是 很可能要么进行非抽水等待,要么处理很长时间 在不发送 Windows 消息的情况下运行操作。这个情况 通常会对性能产生负面影响,甚至可能导致 应用程序变得无响应或内存使用量累积 随着时间的推移不断。为了避免这个问题,所有的单线程 公寓 (STA) 线程应使用泵送等待原语(例如 CoWaitForMultipleHandles)并在长时间内定期发送消息 运行操作。

将代码改为:

  EditingItem.FROM = DateTime.Now;
  EditingItem.TO = DateTime.Now;

对我的情况有帮助。

无法正确谷歌问题,看解释,所以你能帮忙解释一下为什么 whis 表达是错误的吗?
PS 在 cmets 中进行更多讨论。 以下是一些实验结果:

DateTime d = DateTime.Now;
EditingItem.FROM = EditingItem.TO = d;//hang

添加了计时循环:

for (int i = 0; i < 100000; i++)
{
   i++;
}

DateTime d = DateTime.Now;
EditingItem.FROM = EditingItem.TO = d;//hang

【问题讨论】:

  • 与日期时间无关。如果它挂起,则会发生一些问题中未提供的线程同步。
  • @Aliostad,认为你是对的。我添加了例外。但如果它与线程有关——为什么它总是挂在这条线上?
  • 您能解释一下 COM 与DateTime 问题的关系吗? EditingItem的类型是什么?
  • @MartinLiversage,EditingItem 是一些数据库类型,由实体框架提供者生成。我没有在我的代码中使用 COM。我确实使用了 DevExpress 组件(WPF),并且这个初始化发生在我刷新他们的网格之后。可能他们的网格有问题,但对我来说有趣的部分是为什么它挂在这条线上以及为什么初始化分离有帮助??
  • @0x49D1:要解决此问题,请确定涉及的两个线程。一个是用户界面线程,该线程以某种方式被阻塞。另一个后台线程正在尝试访问您的 COM 对象(很可能是 DevExpress 组件),而用户界面线程被阻止。可能还有其他情况,但这是一个可能的候选者。我仍然看不到与DateTime 事物的联系。也许这只是触发您的问题的随机时间问题。 DateTime.Now 有点“慢”,所以引入另一个呼叫会增加一点延迟。

标签: c# datetime declaration


【解决方案1】:

您的问题是似乎发生了lock - 再次没有提供代码,所以只是一个猜测 - 对象被锁定的位置,以便从另一个属性分配一个属性将在自身上死锁。

如果您正在处理 COM,这可以通过 COM 对象是单线程单元对象这一事实来放大。

【讨论】:

  • 对我来说似乎是一个很好的简短解释。尽管我的代码中没有其他线程,我也不在该类中使用锁。
  • @0x49D1:除非涉及至少两个线程,否则锁永远不会死锁。该异常还清楚地标识了两个 COM 上下文或单元,每个上下文或单元至少有一个线程。
【解决方案2】:

您的代码相当于以下内容:

var temp = DateTime.Now;
EditingItem.TO = temp;
EditingItem.FROM = temp;

将赋值放在一行只是一种简写,它可能显示了 C# 的 C 语言根源。

现在您已经提供了有关您的问题的更多信息,您的程序似乎由于 COM 死锁而挂起。很难看出分配DateTime 值会导致死锁。异常表明 CLR 正在尝试调用未处理其消息泵的 STA(单线程单元)中的 COM 对象。

我只是想描述一种可能的情况,但了解您的问题的具体情况我可能还很遥远:

假设您的用户界面中有一个基于 COM 的控件来响应事件(例如单击)。在事件处理程序中启动后台线程,然后事件处理程序等待该线程完成或设置后台任务完成的信号。后台任务(在另一个线程上运行)然后尝试获取 COM 对象的属性。这将触发与您正在经历的死锁类似的死锁。

在 COM 控件以外的另一个单元中运行的后台线程必须将调用编组到 COM 控件(STA)的单元。这是通过向 COM 使用的隐藏窗口发送窗口消息来完成的。但是,应该分派该 Windows 消息的线程当前被阻塞,等待后台线程完成。后台线程正在等待用户界面线程调度 windows 消息。这是一个僵局。

为避免这种情况,切勿阻塞用户界面线程,或者如果您必须至少确保在等待时泵送消息泵。异常消息中暗示了这是如何完成的。

【讨论】:

  • :当然,我知道....添加了例外。认为问题不在于我的变量初始化。
  • 不正确 - 它仅适用于归档或自动属性。这不是等效的 - 在这些属性下可能有代码,在这种情况下。值得-1,但我幸免于难。
  • @MartinLiversage,检查后添加了一些结果。如果我编写您提供的代码 - 它可以正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-12
  • 1970-01-01
  • 2018-01-20
  • 2012-11-09
  • 2012-08-06
  • 1970-01-01
  • 2021-10-04
相关资源
最近更新 更多