【问题标题】:Winforms background worker gets stuckWinforms 后台工作人员卡住了
【发布时间】:2015-03-02 10:44:37
【问题描述】:

我正在尝试构建一个简单的代码,将 csv 文件连接到一个不同的文件中,但我的后台工作人员似乎有自己的想法,我的代码每次都会卡住。 这是我使用后台工作人员加入文件的代码:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            if (string.IsNullOrEmpty(saveFilePath))
            {
                this.Invoke(new MethodInvoker(delegate
                {
                    btnBrowseSave.PerformClick();
                }));
            }
            if (!string.IsNullOrEmpty(saveFilePath))
            {
                if (dragEventArgs != null)
                    files = (string[])dragEventArgs.Data.GetData(DataFormats.FileDrop);

                int filesCount = 0, rowsCount = 0;
                foreach (string file in files)
                {
                    filesCount++;
                    int fileTotalLines = File.ReadAllLines(file).Length;

                    this.Invoke(new MethodInvoker(delegate
                    {
                        lblFileName.Text = "Loading file: " + file.Substring(file.LastIndexOf("\\") + 1);
                        lblTotalFiles.Text = "File " + filesCount + " of " + files.Length;
                    }));

                    using (StreamReader reader = new StreamReader(file))
                    {
                        using (StreamWriter writer = new StreamWriter(saveFilePath))
                        {
                            while (!reader.EndOfStream)
                            {
                                try
                                {
                                    while (stopPosition > rowsCount)
                                    {
                                        reader.ReadLine();
                                        rowsCount++;
                                    }
                                    string email = reader.ReadLine().Trim();
                                    if (!string.IsNullOrEmpty(email) && !dicEmails.ContainsKey(email))
                                    {
                                        dicEmails.Add(email, null);
                                        writer.WriteLine(email);
                                    }
                                    rowsCount++;
                                    stopPosition++;

                                    backgroundWorker.ReportProgress((rowsCount * 100 / fileTotalLines), (int)ProgressType.Row);
                                    if (backgroundWorker.CancellationPending)
                                        return;
                                }
                                catch (Exception ex)
                                {
                                    hadReadErrors = true;
                                }
                            }
                        }
                    }
                    backgroundWorker.ReportProgress(0, (int)ProgressType.Row);
                    backgroundWorker.ReportProgress((filesCount * 100 / files.Length), (int)ProgressType.File);
                }
            }
        }
        catch (Exception ex)
        {
            hadReadErrors = true;
            MessageBox.Show(ex.Message);
        }
        finally
        {
            backgroundWorker.Dispose();
        }
    }

    private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        try
        {
            switch ((int)e.UserState)
            {
                case (int)ProgressType.Row:
                    lblFileProgress.Text = e.ProgressPercentage + "%";
                    fileProgressBar.Value = e.ProgressPercentage;
                    break;
                case (int)ProgressType.File:
                    lblTotalProgress.Text = e.ProgressPercentage + "%";
                    totalProgressBar.Value = e.ProgressPercentage;
                    break;
            }
        }
        catch (Exception ex) { }
    }

当我在调试模式下运行并使用调试器时,我看不到任何问题,但是当我让代码自行运行时,它会卡住并崩溃。 有人可以帮助我并告诉我我在这里错过了什么吗?

这是一个例外:

Managed Debugging Assistant 'ContextSwitchDeadlock' has detected a problem in    
'C:\Users\Develop\Desktop\ExcelBuilder\ExcelBuilder\bin\Debug\ExcelBuilder.vshost.exe'.

Additional information: The CLR has been unable to transition from COM context 0x90fb78 
to COM context 0x90fc30 for 60 seconds. The thread that owns the destination
context/apartment is most likely either doing a non pumping wait or processing a very 
long running operation without pumping Windows messages. This situation generally has 
a negative performance impact and may even lead to the application becoming non 
responsive or memory usage accumulating continually over time. To avoid this problem, 
all single threaded apartment (STA) threads should use pumping wait primitives 
(such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.

【问题讨论】:

  • 有什么异常?定义卡住
  • 进度条不动,主窗体无响应。我在问题中添加了例外,因为它很想发表评论
  • 哪条线路崩溃了,有什么异常?
  • 我在上面的问题中添加了例外,因为它太长了
  • 有多少个文件/行?您可能正在用进度更改淹没消息泵。禁用每行报告,然后重试。

标签: c# winforms backgroundworker


【解决方案1】:

我为你的程序做了一个小例子,试图猜测它必须做什么(https://github.com/anderson-rancan/stackoverflow_28798348,将 4 个文件拖放到 groupbox,lorem?.csv),你应该考虑一些事情:

所以,只要修复它就可以运行它,像这样:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker bckw = (BackgroundWorker)sender; // Recommended way, thread safe

    try
    {
        if (string.IsNullOrEmpty(saveFilePath))
        {
            this.Invoke(new MethodInvoker(delegate
            {
                btnBrowseSave.PerformClick();
            }));
        }
        if (!string.IsNullOrEmpty(saveFilePath))
        {
            if (dragEventArgs != null)
                files = (string[])dragEventArgs.Data.GetData(DataFormats.FileDrop);

            int filesCount = 0, rowsCount = 0;
            foreach (string file in files)
            {
                filesCount++;
                double fileTotalLines = File.ReadAllLines(file).Length;

                this.BeginInvoke(new MethodInvoker(delegate
                {
                    lblFileName.Text = "Loading file: " + file.Substring(file.LastIndexOf("\\") + 1);
                    lblTotalFiles.Text = "File " + filesCount + " of " + files.Length;
                })); // Invoke async, way too fast this...

                using (StreamReader reader = new StreamReader(file))
                {
                    using (StreamWriter writer = new StreamWriter(saveFilePath))
                    {
                        while (!reader.EndOfStream)
                        {
                            try
                            {
                                while (stopPosition > rowsCount)
                                {
                                    reader.ReadLine();
                                    rowsCount++;
                                } // why are you using that? it won't get TRUE

                                string email = reader.ReadLine().Trim();
                                if (!string.IsNullOrEmpty(email) && !dicEmails.ContainsKey(email))
                                {
                                    dicEmails.Add(email, null);
                                    writer.WriteLine(email);
                                }
                                rowsCount++;
                                stopPosition++;

                                bckw.ReportProgress((int)Math.Round(rowsCount * 100 / fileTotalLines, 0), (int)ProgressType.Row);
                                if (bckw.CancellationPending)
                                    return;
                            }
                            catch (Exception ex)
                            {
                                hadReadErrors = true;
                                throw; // Throw it again, or you won't know the Exception
                            }
                        }
                    }
                }
                bckw.ReportProgress(0, (int)ProgressType.Row);
                bckw.ReportProgress((filesCount * 100 / files.Length), (int)ProgressType.File);
            }
        }
    }
    catch (Exception ex)
    {
        hadReadErrors = true;
        MessageBox.Show(ex.Message);
    }
    finally
    {
        bckw.Dispose();
    }
}

private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    //try
    //{
    switch ((int)e.UserState)
    {
        case (int)ProgressType.Row:
            lblFileProgress.Text = e.ProgressPercentage + "%";
            if (e.ProgressPercentage <= fileProgressBar.Maximum)
                fileProgressBar.Value = e.ProgressPercentage;
            break;
        case (int)ProgressType.File:
            lblTotalProgress.Text = e.ProgressPercentage + "%";
            totalProgressBar.Value = e.ProgressPercentage;
            break;
    }
    //}
    //catch (Exception ex) { } // Don't catch everything
}

最后,我可以建议另一种方法吗? 您正在读取文件两次:一次获取行数,另一次读取每一行。尝试这样做一次,你会得到更好的结果。

【讨论】:

  • 非常感谢您的出色回答 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-11
  • 1970-01-01
  • 2014-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多