【问题标题】:Worker Threads Blocking When ConcurrentQueue has too many items当 ConcurrentQueue 有太多项目时工作线程阻塞
【发布时间】:2017-01-05 15:47:44
【问题描述】:

这很奇怪,我有一个Thread[] 的工作线程,每个工作线程处理ConcurrentQueue<string> 中的项目,直到队列为空,此时程序的其余部分继续。

这一直有效,直到大约 1500 个项目,此时所有线程都保持阻塞在 WaitSleepJoin 状态,并且永远不会处理队列中的任何项目。

我已尝试单步执行我的代码,但线程似乎仍在创建、仍在启动且处于活动状态,但立即被阻塞且从未运行其相关功能。

我完全糊涂了,所以任何帮助都将不胜感激!

相关部分代码如下:

主线程段:

            ConcurrentQueue<string> convertionQueue = new ConcurrentQueue<string>();
            List<Thread> converterThreads = new List<Thread>();
            Directory.GetFiles(_folderOne, "*.fdf", SearchOption.AllDirectories).ToList().ForEach(file => convertionQueue.Enqueue(file));
            Directory.GetFiles(_folderTwo, "*.fdf", SearchOption.AllDirectories).ToList().ForEach(file => convertionQueue.Enqueue(file));
            int filesDone = 0;
            int totalFiles = convertionQueue.Count;
            progressBar.Maximum = totalFiles;
            panel1.Visible = true;
            for (int i = 0; i < Environment.ProcessorCount; i++)
            {
                converterThreads.Add(new Thread(() => ConvThreadWorker(convertionQueue, ref filesDone)));
            }
            converterThreads.ForEach(thread => thread.Start());
            DateTime lastTick = DateTime.Now;
            int lastFilesDone = 0;
            int[] valuesSpeed = { 1, 1, 1, 1, 1 };
            int[] valuesTime = { 1, 1, 1, 1, 1 };
            int counter = 0;
            while (converterThreads.Any(thread => thread.IsAlive))
            {

                TimeSpan t = DateTime.Now - lastTick;
                int deltaFiles = filesDone - lastFilesDone;
                double speed = (float)t.TotalMilliseconds <= 0.0 ? 0.0 : deltaFiles / (float)t.TotalMilliseconds;
                double tMinus = speed <= 0 ? 0.0 : (totalFiles - filesDone) / speed;
                int currentSpeed = (int)(speed * 1000);
                int currentTime = (int)(tMinus / 1000);
                valuesSpeed[counter] = currentSpeed;
                valuesTime[counter] = currentTime;
                lblFilesLeft.Text = string.Format("{0}/{1}", filesDone, totalFiles);
                lblSpeed.Text = valuesSpeed.Sum() / 5 + " /s";
                lblTime.Text = valuesTime.Sum() / 5 + " s";
                lblFilesLeft.Update();
                lblSpeed.Update();
                lblTime.Update();
                progressBar.Value = filesDone;
                progressBar.Update();
                lastTick = DateTime.Now;
                lastFilesDone = filesDone;
                counter = ++counter % 5;
                Thread.Sleep(500);
            }

工人函数:

private void ConvThreadWorker(ConcurrentQueue<string> queue, ref int fileCounter)
{
    while (!queue.IsEmpty)
    {
        string file;
        if (queue.TryDequeue(out file))
        {
            ConvToG(file);
            fileCounter++;
        }
    }
}

转换函数:

private void ConvToG(string file)
{
    MessageBox.Show("Entering Convertion Function");
    if (!_fileCreationDictionary.ContainsKey(file))
    {
        DateTime lastTimeModified = File.GetLastWriteTime(file);
       _fileCreationDictionary.AddOrUpdate(file, lastTimeModified, (key,oldvalue)=>lastTimeModified);
    }
    ProcessStartInfo procStart = new ProcessStartInfo
    {
        Arguments = file,
        UseShellExecute = true,
        FileName = Fdfg,
        WindowStyle = ProcessWindowStyle.Hidden
    };
    Process process = new Process {StartInfo = procStart};
    MessageBox.Show("Starting convertion process");
    process.Start();
    process.WaitForExit();
    MessageBox.Show("Finished");
}

令人困惑的部分似乎是这一切是如何围绕队列中的项目数进行的,但似乎没有溢出。

更新:添加 mbox 表明它在代码的 process.Start() 部分冻结,没有错误,并且不会超过该点。

更新 2:如果 UseShellExecute = false 代码有效。至少可以说这非常令人困惑。

【问题讨论】:

  • 你完全饿死了应用程序消息泵。我不确定没有空气它还能存活多久。
  • 已添加 1500 个文件,在阻止之前它不会处理任何文件
  • @HenkHolterman 这不应该花费超过 20 秒的时间来运行,并且只是一个内部工具,所以如果 windows 决定它没有响应,我们不会大惊小怪
  • 您确定没有任何内容正在处理? (而不仅仅是一个进度条错误)。它挂在哪里? While 循环是否正在运行?
  • 设置 UseShellExectute = false 似乎可以完成这项工作,不知道为什么这似乎取决于文件数量

标签: c# multithreading winforms thread-safety concurrent-queue


【解决方案1】:

我已经对线程产生进程来整理数据做了类似的事情。我在实际过程的启动和挂起方面遇到了问题。我为使程序正常工作所做的事情是这样的:

using (Process process = Process.Start(startInfo)) {
    if(process.WaitForExit(timeOutMilliseconds)) {
        MessageBox.Show("Process exited ok");
        //...snip
    } else {
        MessageBox.Show("Process did not exit in time!");
        //...snip
        process.Kill();
    }
}

在后台有更多的事情发生,关于限制运行进程的数量等,但我发现偶尔,由于未知的原因,我会看到任务管理器中的几个进程永远挂着。

希望有帮助吗?

【讨论】:

  • 这有帮助,谢谢。不知道为什么会挂起。
猜你喜欢
  • 2013-03-30
  • 2021-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多