多线程控制台应用程序阵列死锁

时间:2018-09-26 00:06:56

标签: c# multithreading deadlock

最近我一直在努力解决多线程问题。我有一个训练神经网络的C#控制台应用程序。我通过任务为每个要训练的网络生成线程。我为我的上级课程所预订的教练课程创建了状态更新事件。在该事件处理程序中,我使用该模型的新状态更新状态数组。该阵列访问是我看到“死锁”类型行为的地方。我知道这不是死锁的规范定义,但是我想不出更好的术语来描述这种情况。下面是我的代码。我已经尽力了。

感谢您的帮助。谢谢

父代码

public class TrainingEngine
{
    public enum UpdateStatus
    {
        Untrimmed = 0,
        Trimmed,
        Completed
    }

    private class TrainingStatus
    {
        public int Epoch { get; set; }
        public UpdateStatus UpdateStatus { get; set; }
    }

    private static readonly object printLock = new object();

    private ConcurrentDictionary<int, TrainingStatus> trainingStatus;

    ...other stuff...

    private void UpdateEpochCompleted(TrainingStatus newStatus)
    {
        trainingStatus[newStatus.ThreadId] = newStatus;
        PrintUpdate($"Model {newStatus.ThreadId + 1} completed epoch {newStatus.Epoch}.");
    }

    private void PrintUpdate(string trigger)
    {
        lock (printLock)
        {
            logger.Info(""); /***** DEADLOCKS HERE *****/

            logger.Info($"  {trigger}");
            foreach (TrainingStatus status in trainingStatus.Values)
            {
                if (status.Status == TrainingStatus.UpdateStatus.Completed)
                {
                    logger.Info(
                        $"    {status.Status.ToString()} model {status.ThreadId + 1}",
                        100);
                }
                else
                {
                    logger.Info(
                        $"    {status.Status.ToString()} model {status.ThreadId + 1} working on epoch {status.Epoch} / {epochCount}",
                        100);
                }
            }
        }
    }
}

工人定义

public class NetworkTrainer
{
    IProgress<TrainingStatus> UpdateCompleted { get; set; }


        private double TrainNetwork(ActivationNetwork network,
            int epochCount,
            int geneCount,
            double[][] inputData,
            double[][] outputData,
            int threadId,
            bool trimmedModel)
        {

            for (int idxEpoch = 0; idxEpoch < epochCount; ++idxEpoch)
            {
                error += teacher.RunEpoch(inputData,
                    outputData);

                UpdateCompleted?.Report(new TrainingStatus
                {
                    Epoch = idxEpoch,
                    Status =  (trimmedModel) ? TrainingStatus.UpdateStatus.Trimmed : TrainingStatus.UpdateStatus.Untrimmed,
                    ThreadId = threadId,
                });
            }

            return error;
        }
}

死锁屏幕截图 enter image description here

1 个答案:

答案 0 :(得分:1)

我发现了问题。首先,我要感谢所有帮助过我的人,特别是Panagiotis Kanavos和usr。最初,我有一个写得不好的锁声明,很容易被重入。查看我的代码,我看不到这种情况如何发生。毕竟,每次训练大约需要30分钟。经过一番调查,我了解到,当我单击终端窗口并在窗口上留下一个白色正方形(标记)时,我已锁定访问终端。这意味着我的线程不再能够写入终端。我造成了僵局。有时,在笔记本电脑训练模型时,我会在笔记本电脑上做其他事情,然后单击终端以查看当前状态。

tl;博士如果单击终端,请按Enter键将其释放回系统。