【发布时间】:2010-12-30 04:03:53
【问题描述】:
在对我的任务调度程序进行了某个阶段的测试后,我几乎随机遇到了死锁。我想寻求一些帮助,特别是我想知道我的方法是否会陷入僵局,或者问题是否出在其他地方。
在开始之前,我会说该应用程序是一个全屏游戏。 (以防它可能影响任何事情)
我会用文字解释系统是如何工作的。
任务调度器
1) 在每帧开始时为每个 CPU 调度 2 个任务。 (通过调度我的意思是将任务的私有 WaitHandle 设置为允许任务做一些工作)
这是一个简短的代码,总结了系统对这两个任务中的每一个所做的事情。
Scheduled++;
InternalLock.Reset();
所有两个任务都安排好后,通过设置私有 WaitHandle 来启动它们。
2) 等待所有任务完成。等待是通过等待每个任务必须发出信号的内部 WaitHandle 来完成的。 (WaitOne() 在每个任务上)
这是等待的代码:
if (Attese.Length > 0)
{
TmpIsSucceded = false;
for (int i = 0; i < Attese.Length; i++)
{
WaitHandle actual = Attese[i].Wait;
do
{
TmpIsSucceded = actual.WaitOne(150);
if (!TmpIsSucceded)
EnginesManager.ProcessMessages();
} while (!TmpIsSucceded);
}
}
任务
1) 直到游戏结束才关闭。
2) 有 2 个内部 WaitHandle。一位私人告诉他有工作时的任务。当任务结束其工作时发出的一个内部信号。 (任务调度程序正在等待的那个)
3) 当任务自己完成时,在任务调度程序的同步(通过 lock())队列中启动另一个可用的任务(以相同的方式通过设置该任务的私有等待句柄)。
这是任务的主循环:
private void CoreThread()
{
while (_active)
{
PrivateLock.WaitOne(-1, false);
while (Scheduled > 0)
{
if (OnThreadExecute != null)
OnThreadExecute(this, null);
Scheduled--;
if (Scheduled == 0)
{
PrivateLock.Reset();
if (OnThreadEnd != null)
OnThreadEnd(this, null);
InternalLock.Set();
}
}
}
}
InternalLock 和 PrivateLock 是两个等待句柄。请注意,InternalLock 等待句柄仅在此代码中设置。没有其他地方设置了 InternalLock 或 PrivateLock。 (除了我贴的代码)
当死锁发生时,任务调度程序正在等待所有任务完成,但其中一项任务从未设置 InternalLock 等待句柄。 “阻塞”任务在“PrivateLock.WaitOne(-1, false);”处停止发生死锁时的行。
有人知道这个僵局吗?
编辑:
internal void StartSchedule()
{
for (int i = 0; i < Tasks.Length; i++)
{
if (Tasks[i].Schedule())
QTasks.Enqueue(Tasks[i]);
}
StartThreadAvailable();
}
private void StartThreadAvailable()
{
TempExecList.Clear();
for (int i = 0; i < NThread; i++)
{
if (QTasks.Count > 0)
TempExecList.Add(QTasks.Dequeue());
}
Int32 count = TempExecList.Count;
for (int i = 0; i < count; i++)
TempExecList[i].StartThread();
}
internal void StartThread()
{
PrivateLock.Set();
}
这是按要求调用私有句柄的 Set() 的代码。
Schedule() 在这种情况下总是返回 true。 (它只是将任务的计划变量加1并重置InternalLock)
编辑 2:
这是所要求的 2 个类的代码:
【问题讨论】:
-
请出示包含
PrivateLock.Set()的代码 -
你是如何声明等待句柄的?你能发布一个完整的编译示例吗?
-
如果您想要TaskScheduler 和GameTask 这两个类,我可以发帖,但正如我所说,这是一个非常随机的错误,因此您不能依赖运行几个小时后可能会失败的示例。 XD
-
你需要用一个测试用例打破代码以隔离棘手的东西,但你绝对需要清理同步,你正在从多个未同步的线程访问状态
-
虽然我没有答案,但我觉得有义务指出“用保护替换嵌套”重构 - refactoring.com/catalog/…
标签: c# .net multithreading deadlock