user1451772
user1451772

Reputation: 21

My BackgroundWorker still blocks my UI

I have a time consuming method in a class that's buried in a .dll which I don't have the source for. I don't want to block the UI when I call this method. I've been trying to use a BackgroundWorker to do this. I call RunWorkerAsync from a btn_Click event handler. When I have the dllClass instance created outside of the worker thread (like below) the UI freezes until the operation is finished. The operation also blocks the timer from ever ticking.

public static dllClass dllClassInstance = new dllClass();

void worker1_DoWork(object sender, DoWorkEventArgs e)
{
    dllClassInstance.TimeConsumingMethod();
}

On the other hand if I instance the class inside the worker thread (like the next code segment) it works as intended.

void worker1_DoWork(object sender, DoWorkEventArgs e)
{
    dllClass dllClassInstance = new dllClass();

    dllClassInstance.TimeConsumingMethod();
}

The issue with using the latter is that I need access to the class instance outside of that specific worker, since I have to call other methods before and after the time consuming method. I also tried passing the class instance into the BackgroundWorker through e.Argument but it also resulted in the UI freezing. Does anyone have suggestions how to call that method without blocking the UI?

Upvotes: 2

Views: 2812

Answers (4)

Perfect Tommy
Perfect Tommy

Reputation: 7

I am working on a VB.net application and came across the same issue with the Visa Com 3.0 drivers for communication with Agilent devices. Here is how I solved it:

Dim task = New Threading.Tasks.Task(Of dllClass)(Function()
                                                     Return New dllClass()
                                                 End Function)
task.Start()
task.Wait()

public static dllClass dllClassInstance = task.Result;

void worker1_DoWork(object sender, DoWorkEventArgs e)
{
    dllClassInstance.TimeConsumingMethod();
}

Essentially I create my dllClass instance in a new thread, but immediately discard that thread and hold on to the reference.

Upvotes: 0

DRapp
DRapp

Reputation: 48179

As Reed pointed out, it may be hard to really resolve without knowing what the internals of that class are. However, if you have other stuff you need to load / prepare, setup, I would have your background worker class "ReportsProgress" = true, and when it starts, immediately call a method that will grab and/or prepare other settings based on ex: a progress of 1 (starting), then, do your other element of the long process, then report progress coming out with value like 99 (end) and do some cleanup from that.

Does this sound like it would help? You could still have it all encapsulated into a single background worker class.

Upvotes: 0

zmbq
zmbq

Reputation: 39079

It's probably because of your dllClass. What you're seeing shouldn't happen, unless someone wants to make sure all calls on an instance are processed in the same thread. If dllClass takes the dispatcher in its constructor, and then TimeConsumingMethod invokes the actual processing through that dispatcher, you're going to see frozen UI.

Upvotes: 1

Reed Copsey
Reed Copsey

Reputation: 564931

Does anyone have suggestions how to call that method without blocking the UI?

Without knowing what's happening within dllClass, it's impossible to determine.

Neither code, normally, would cause the UI to freeze. I suspect dllClass is capturing the current SynchronizationContext within its constructor, and using it internally within TimeConsumingMethod, causing blocking. If this is the case, you could likely construct the class within your DoWork handler, but have it scoped to the class instead, which would likely work. However, if it is capturing the synchronization context, then the class is likely to have thread affinity and expect to be running on the UI thread.

You could try constructing the instance within the handler, like so:

public dllClass dllClassInstance;

void worker1_DoWork(object sender, DoWorkEventArgs e)
{
    dllClassInstance = new dllClass(); // Construct here
    dllClassInstance.TimeConsumingMethod();
}

This may work, though, as I said, it may have other side effects. I would verify that dllClass doesn't have thread affinity rules which require it to run on the UI thread.

Upvotes: 3

Related Questions