C# 协作/非抢占式线程避免死锁?

C# 协作/非抢占式线程避免死锁?,c#,multithreading,deadlock,contextswitchdeadlock,C#,Multithreading,Deadlock,Contextswitchdeadlock,有没有创造性的想法可以避免在不执行O/S线程的情况下,通过协作/非抢占式多任务处理在产量或睡眠方面出现死锁?睡眠(10)?通常,yield或sleep调用将回调调度程序以运行其他任务。但这有时会造成死锁 一些背景: 这个应用程序对速度有着巨大的需求,而且到目前为止,与同行业的其他系统相比,它的速度非常快。速度技术之一是协作/非抢占式线程,而不是O/S线程上下文切换的成本 高级设计是一个优先级管理器,它根据优先级和处理时间调用任务。每个任务执行一次“迭代”工作,并返回优先级队列再次等待轮到它 一个

有没有创造性的想法可以避免在不执行O/S线程的情况下,通过协作/非抢占式多任务处理在产量或睡眠方面出现死锁?睡眠(10)?通常,yield或sleep调用将回调调度程序以运行其他任务。但这有时会造成死锁

一些背景:

这个应用程序对速度有着巨大的需求,而且到目前为止,与同行业的其他系统相比,它的速度非常快。速度技术之一是协作/非抢占式线程,而不是O/S线程上下文切换的成本

高级设计是一个优先级管理器,它根据优先级和处理时间调用任务。每个任务执行一次“迭代”工作,并返回优先级队列再次等待轮到它

一个棘手的问题,就是当你想让一个特定的任务在工作中间停下来,在继续之前等待其他任务的时候,该如何做。


在本例中,我们有3个任务,A是B和C,其中A是一个控制器,必须同步B和C的活动。首先,A启动B和C。然后B产生,所以C被调用。当C生成时,A看到它们都处于非活动状态,决定是B运行的时候了,而不是C运行的时候了。B井现在被困在一个称为C的产量中,因此它永远无法运行。

我认为处理这个问题最干净的方法可能是将产量(一个线程决定它已经处理了足够一段时间)与阻塞(等待特定事件)分开。这使得给已经屈服的线程留出时间相对容易,但避免了在试图运行被阻塞的线程时出现死锁。通常,您希望对阻塞的线程和其他线程进行拓扑排序,以便为其他线程等待的线程留出时间。这应该会给出一个DAG——图中的任何循环都表示死锁。

好吧,如果C语言支持真正的“continuations”来展开堆栈并在稍后停止的地方继续,这将是理想的解决方案

在此情况下,我们正在通过允许这种情况下的任务将“isInterrupted”标志设置为true并返回来进行我们自己的临时替换——从而展开堆栈

然后,当调度器想要再次为该任务安排处理时间时,它将看到isInterrupted并跳过已经完成的处理,使用简单的if语句直接跳到中断位置

真诚地,
韦恩

好的,很好。更多信息:我们已经这样做了。我们通过一个任务处理的所谓的“屈服”只是执行一个返回操作,以便堆栈展开回到调度程序。这意味着这个问题讨论中所有的收益和睡眠都被阻塞了。这样:while(!xevent)Yield();我们已经处理了DAG,这解决了所有其他情况。但是上面问题中的一个,如果你更仔细地研究它的话,并不是这样解决的。B和C之间没有依赖关系,只是它们必须同步。因此,它们必须每次暂停并等待下一个运行的通知。这里的基本问题是,每个任务在等待时都会绑定堆栈。一个混乱的解决方案是将B和C分成两个任务。所以B变成B1和B2。这样B1和B2可以通过来回切换状态来运行。如果需要位于B1末尾的块,以便在禁用B2后可以退出任务,这样B2在a重新激活之前不会开始运行。这样,堆栈在两种情况下都会被释放。把可爱的代码分割成这样的碎片是很难看的。但是如果没有更好的办法,也许我只是睡眠不足,但我仍然没有完全理解这个问题。哪个线程具有
while(!xevent)Yield(),您希望设置哪些
xevent
?稍微改变一下规则,就会有一种完全不同的可能性:使用协作多任务来减少开销,但使用看门狗定时器,只有在死锁时才抢占。这是一个聪明的想法。唯一的问题是,如果它在死锁期间进行抢占,那么需要运行的任务中仍然有另一个线程阻塞。为了继续,抢占线程需要重新输入该任务,这将使该任务需要线程安全代码。这个系统的美妙之处在于,所有任务都可以非线程安全地编写(简单!),因为它们保证永远不会被其他线程重新进入。当然,他们可能会在任何执行中得到不同的线程,但一次只能得到一个线程。我们想出了一个尝试的想法。我们正在考虑使用属性“IsDeadlockable”手动标记这些“危险”任务。然后,如果一个线程在一个任务中处于屈服或休眠状态,则不允许它进入另一个标记为“IsDeadlockable”的任务。我认为这将解决这一具体情况。不幸的是,它不是一个自动发现。我们看不到任何方法可以自动预见和防止这样的僵局。这是因为调度器只知道它会在死锁发生后死锁,然后在不破坏程序逻辑的情况下不可能释放堆栈。有趣的问题。标记为C#,因为您的答案似乎表明您使用的是这种语言。