|
|
1
44
后退一步。 首先指定所有需要和不需要的特性 之前 你开始写一个解决方案。一些立刻想到:
这总结了问题空间吗? 首先,我注意到 似乎 乍一看,问题是u必须是d()的调用方。如果w是d()的调用者,那么就不必担心了;您只需要向w发出信号,使其脱离循环,然后w会在循环之后调用d()。但这只是将一个问题换成另一个问题;在这种情况下,您必须等待w调用d(),然后才能调用exit()。因此,将对d()的调用从u移动到w实际上并不能使问题更简单。 你说过你不想使用双重检查锁定。您应该知道,从clr v2开始,双重检查的锁定模式是安全的。V2增强了内存模型保证。所以使用双重检查锁定可能是安全的。 更新:您询问了有关(1)为什么在v2而不是v1中双重检查锁定安全的信息?为什么我用黄鼠狼的词“可能”? 要了解为什么双重检查锁定在clr v1内存模型中不安全,但在clr v2内存模型中安全,请阅读以下内容: http://web.archive.org/web/20150326171404/https://msdn.microsoft.com/en-us/magazine/cc163715.aspx 我说“可能”,因为正如乔·达菲明智地说:
我不知道您是否计划正确地使用双重检查锁定,或者您是否计划编写自己的巧妙的、中断的双重检查锁定变体,实际上在IA64机器上会死机。因此,它将 可能 为你工作,如果你的问题真的可以接受双重检查锁定 和 你写的代码是正确的。 如果你关心这个,你应该读乔·达菲的文章: http://www.bluebytesoftware.com/blog/2006/01/26/BrokenVariantsOnDoublecheckedLocking.aspx 和 http://www.bluebytesoftware.com/blog/2007/02/19/RevisitedBrokenVariantsOnDoubleCheckedLocking.aspx 所以这个问题有一些很好的讨论: The need for volatile modifier in double checked locking in .NET 也许最好是找到一些其他机制,而不是双重检查锁定。 有一种机制可以等待正在关闭的一个线程完成——thread.join。您可以从UI线程连接到工作线程;当工作线程关闭时,UI线程将再次唤醒并进行释放。 更新:添加了一些有关join的信息。 “join”的基本意思是“线程u告诉线程w关闭,而u进入睡眠状态直到这发生”。退出方法简图:
假设您出于某种原因不想使用“join”。(可能工作线程需要继续运行才能执行其他操作,但您仍然需要知道使用对象何时完成。)我们可以构建自己的机制,其工作方式与使用等待句柄进行联接类似。你现在需要的是 二 锁定机制:一个让你向W发送一个信号,表示“现在停止运行”,另一个则表示 等待 当w结束对m()的最后一个调用时。 在这种情况下,我会做的是:
所以,简单的草图: UI线程,启动逻辑:
UI线程,退出逻辑:
工作者线程:
注意,这取决于m()是短的。如果m()需要很长时间,那么您可以等待很长时间来退出应用程序,这似乎很糟糕。 这有道理吗? 其实,你不应该这样做。如果要在释放工作线程正在使用的对象之前等待其关闭,只需将其联接。 更新:提出了一些其他问题:
事实上,请注意,在我的join示例和waitone示例中,我不使用在放弃之前等待特定时间的变量。相反,我指出我的假设是工作线程会快速而干净地关闭。这是正确的做法吗? 这要看情况!这取决于工作线程的行为有多糟糕,以及当它行为不端时它在做什么。 如果你能保证工作持续时间很短,不管“短”对你意味着什么,那么你不需要超时。如果您不能保证,那么我建议您首先重写代码,以便 可以 保证;如果你知道代码在你要求的时候会很快终止,生活就会变得容易得多。 如果你不能,那你该怎么做?这种情况的假设是,工人行为不端,在被要求时不会及时终止。所以现在我们要问自己“是工人吗? 设计慢 ,请 婴儿车 或 怀有敌意的 ?“ 在第一种情况下,工人只是做了一些需要很长时间的事情,无论出于什么原因,都不能被打断。在这里做什么是正确的?我不知道。这是一个可怕的情况。可能工人没有很快关闭,因为这样做是危险的或不可能的。在这种情况下,当超时超时时,您要做什么????你有一些危险的或者不可能关闭的东西,而且它没有及时关闭。你的选择似乎是:(1)什么都不做,(2)做一些危险的事情,或(3)做一些不可能的事情。第三种选择可能会被淘汰。选择一等于永远等待,因为我们已经拒绝了。这就意味着“做一些危险的事情”。 了解正确的操作以尽量减少对用户数据的伤害取决于造成危险的具体情况;仔细分析,了解所有情况,并找出正确的操作。 现在假设工人应该能够快速关闭,但不是因为它有一个bug。很明显,如果可以的话,修复这个bug。如果您不能修复这个bug——也许它是在您不拥有的代码中——那么,您再次陷入了一个糟糕的修复中。您必须了解不等待已经出现错误的结果,因此在处理您知道它正在另一个线程上使用的资源之前,不可预知的代码会完成。当一个有缺陷的工作线程仍在忙着工作时,您必须知道终止应用程序的后果是什么,天堂只知道操作系统状态是什么。 如果代码是 怀有敌意的 而且是 积极抵制关闭 那么你已经输了。你不能用正常的方法终止线程,甚至不能中止线程。无法保证中止一个敌对线程实际上会终止它;您在进程中愚蠢地开始运行的敌对代码的所有者可以在finally块或其他约束区域中完成其所有工作,从而防止线程中止异常。 最好的办法是一开始就不要陷入这种情况;如果你有你认为是敌对的代码,要么根本不要运行它,要么在它自己的进程中运行它,然后终止 过程 不是 线程 当情况恶化时。 简而言之,“如果时间太长,我该怎么做?”这个问题没有很好的答案。你在A 可怕的 如果发生这种情况,就没有简单的答案。最好努力工作,以确保你一开始不会接触到它;只运行合作的、良性的、安全的代码,当被要求时,它总是以干净和快速的方式关闭自己。
好吧,如果有呢?同样,最好不要在这种情况下出现;编写工作者代码,使其不抛出。如果您不能这样做,那么您有两个选择:处理异常,或者不处理异常。 假设您不处理异常。至于clr v2,工作线程中未处理的异常会关闭整个应用程序。原因是,在过去会发生的事情是,你会启动一组工作线程,它们都会抛出异常,最后你会得到一个运行中的应用程序,没有留下工作线程,没有做任何工作,也没有告诉用户。最好是强制代码的作者处理工作线程因异常而停机的情况;使用旧方法可以有效地隐藏错误并使编写脆弱的应用程序变得容易。 假设您确实处理了异常。现在怎么办?某个事件引发了异常,根据定义,这是一个意外的错误条件。您现在不知道您的任何数据是一致的,或者您的任何子系统中维护了任何程序不变量。那你打算怎么办?在这一点上你几乎没有什么安全的事可以做。 问题是“在这种不幸的情况下,什么对用户最好?”这取决于应用程序正在做什么。在这一点上,最好的做法是简单地主动关闭并告诉用户意外的失败。这可能比在试图清理时不小心破坏了用户数据,可能会使情况变得更糟要好。 或者,完全有可能的是,最好的做法是真诚地努力保存用户的数据,尽可能地整理状态,并尽可能正常地终止。 基本上,您的两个问题都是“当我的子系统不工作时,我该怎么做?”如果你的子系统不可靠,或者 使它们可靠 或 对如何处理不可靠的子系统制定策略,并实现该策略 . 这是一个模糊的答案,我知道,但那是因为处理一个不可靠的子系统是一个固有的可怕的情况。如何处理它取决于它的不可靠性的性质,以及这种不可靠性对用户宝贵数据的影响。 |
|
|
2
6
检查
你甚至可以把它改写为
|
|
|
3
0
而不是使用
这样,当
编辑:这里有代码,快速和肮脏,没有测试等。
|
|
|
BlurKid · R中for循环时结果的奇怪差异 10 月前 |
|
|
bigjdawg43 · 迭代多个数据帧中的列并有条件地执行操作 1 年前 |
|
|
xhamsterIT · 循环VBA Microsoft Excel 1 年前 |
|
|
Nico44044 · 使用for循环遍历Django模型字段 1 年前 |
|
|
chanbo chung · 如何在聚合中获得所有可能的组合 1 年前 |
|
|
Himanshu · 无法在逐行二进制搜索中迭代2D数组中的所有行 1 年前 |
|
|
stephr · 循环为多个变量选择最接近另一个日期的日期 1 年前 |