Method accessed by more than one thread in C# Using Progressbar

血红的双手。 提交于 2019-12-22 00:27:15

问题


I have multiple threads accessing a method.

That method updates the progress bar on the form as the threads execute.

That method updates the progress bar on my windows form showing the progress of the processed files as the threads are completing them.

How would you go about managing that method to avoid deadlocks. Im having trouble locking it, dont know if im doing it wrong, or if i should lock it in this case.

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);

        }

What happens is, that at the last line, it breaks telling me that "This operation has already had OperationCompleted called on it and further calls are illegal."

I take it that im opening something that has already been disposed by the first thread or something like that.

Is this a good way to go about using the progress bar with multiple threads (do i have the right idea or principle), or is there just a small error in my code?

How I want to make this question valuable for other people is to answer with this question how global variables can be accessed inside a method that's being accessed by multiple threads. since i take it thats the direction this question is going in.


回答1:


It looks like you're using the BackgroundWorker class, which I'm not familiar with.

But you're also asking for a "generic" design for using multiple threads and ProgressBar. This example would be my way for updating a ProgressBar from a number of threads.

First, you need a public delegate (probably in some helper-class)

//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;
    }
}

In each worker class you must register the delegate

// event for reporting progress
private event ProgressChangedHandler ProgressChanged;

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

In the UI class which holds the ProgressBar you need a method for updating the progress. But every call to that method is executed in the thread of the caller (which can be problematic with the not-threadsafe UI).

To avoid this, you can call the dispatcher, so that every raised event will be handled in your UI thread and not the worker thread.

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;
    }
}

This method you can pass to the worker as delegate

worker.RegisterEventHandler(StatusUpdate);

Finally you can call the delegate via an event from every thread

public void DoVeryHardWork()
{
    // do stuff
    ProgressChanged(this, new ProgressEventArgs(progress, "some message"));
}


来源:https://stackoverflow.com/questions/12812725/method-accessed-by-more-than-one-thread-in-c-sharp-using-progressbar

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!