1

我有多个线程访问一个方法。

当线程执行时,该方法会更新表单上的进度条。

该方法会更新我的 Windows 窗体上的进度条,显示线程正在完成它们时处理文件的进度。

您将如何管理该方法以避免死锁。我无法锁定它,不知道我是否做错了,或者在这种情况下我是否应该锁定它。

public void myWorkerClass()
        {
            int amountToScan = 4;

            lblcount.BeginInvoke(
               ((Action)(() => lblcount.Text = "Files Checked " + atPDFNumber.ToString() + " of " + amountToScan.ToString())));

            decimal percentageComplete = ((decimal)atPDFNumber / (decimal)amountToScan) * 100;

            backgroundWorker1.ReportProgress((int)percentageComplete);

        }

发生的情况是,在最后一行,它告诉我“这个操作已经调用了 OperationCompleted 并且进一步的调用是非法的”。

我认为我打开了已经由第一个线程或类似的东西处理的东西。

这是使用多线程进度条的好方法(我有正确的想法或原则),还是我的代码中只有一个小错误?

我想让这个问题对其他人有价值的方法是用这个问题来回答如何在多个线程访问的方法中访问全局变量。因为我认为这就是这个问题的方向。

4

1 回答 1

2

看起来您正在使用我不熟悉的 BackgroundWorker 类。

但是您还要求使用多线程和 ProgressBar 的“通用”设计。这个例子是我从多个线程更新 ProgressBar 的方式。

首先,您需要一个公共代表(可能在某个助手类中)

//is called when the worker-progress is changed
public delegate void ProgressChangedHandler(object sender, ProgressEventArgs e);

// some own EventArgs
public class ProgressEventArgs : EventArgs
{
    public int Percentage { get; private set; }

    public string Message { get; private set; }

    public ProgressEventArgs(int percentage, string message)
    {
        Percentage = percentage;
        Message = message;
    }
}

在每个工人阶级中,您必须注册代表

// event for reporting progress
private event ProgressChangedHandler ProgressChanged;

// register Eventhandler via dependency injection or own method
public void RegisterDelegate(ProgressChangedHandler progressChangedHandler)
{
    ProgressChanged += progressChangedHandler;
}

在包含 ProgressBar 的 UI 类中,您需要一个更新进度的方法。但是对该方法的每次调用都在调用者的线程中执行(这对于非线程安全的 UI 可能会出现问题)。

为避免这种情况,您可以调用调度程序,以便每个引发的事件都将在您的 UI 线程而不是工作线程中处理。

private void StatusUpdate(object sender, ProgressEventArgs args)
{    
    if (Dispatcher.Thread.ManagedThreadId != Thread.CurrentThread.ManagedThreadId)
    {
        // call from a worker thread
        var statusUpdateDelegate = new ProgressChangedHandler(this.StatusUpdate);

        Dispatcher.Invoke(statusUpdateDelegate, DispatcherPriority.Normal, sender, args);
    }
    else
    {
        // direct call from the UI thread
        lblProgress.Content = args.Message;
        pbProgress.Value = args.Percentage;
    }
}

您可以将此方法作为委托传递给工作人员

worker.RegisterEventHandler(StatusUpdate);

最后,您可以通过每个线程的事件调用委托

public void DoVeryHardWork()
{
    // do stuff
    ProgressChanged(this, new ProgressEventArgs(progress, "some message"));
}
于 2012-10-10T13:18:32.893 回答