views:

71

answers:

3

Hi,

Can some kind soul please explain why the following psudocode would not work. The problem is that the lock can never be aquired on the backgroundWorker (Monitor.TryEnter(bw)) when called from a new thread. If I call it from the main UI thread it works fine.

Thanks P

public class MyClass 
{
    private BackgroundWorker bw;

    private void Button_Click(object sender, EventArgs e)
    {
        System.Threading.Thread t = 
            new System.Threading.Thread(new System.Threading.ThreadStart(DoStuff));
        t.IsBackground = true;
        t.Start();
    }

    private void DoStuff()
    {

        if (Monitor.TryEnter(bw))
        {
              WorkDetails wd = new WorkDetails('some stuff here');
              bw.RunWorkerAsync(wd);

              // etc... etc...
        }
    }
}
+1  A: 

Are you missing a Monitor.Exit at the end of the if block. Without a Monitor.Exit, whichever thread first does a Monitor.TryEnter successfully will be the only thread that can enter again.

Scott Langham
It can ne a possible cause +1 for this
saurabh
A: 

Try with simple lock keywork rather than using Moniter.TryEnter

saurabh
+1  A: 

I'm not sure you are using the background worker (BGW) as it was intended

The idea behind it, usually, is that you don't create threads yourself but rather specify to the BGW what you want to be done asynchronously. so your code should look like:

private BackgroundWorker bw = new BackgroundWorker ();
ctor 
{
    bw.DoWork += (sender, e) => DoStuff();
}

private void Button_Click(object sender, EventArgs e)
{
    bw.RunWorkerAsync();
}

For more information, see here

comments:

  1. As a rule of thumb, never lock on arbitrary objects (like you do on bw) but rather on objects whose sole purpose is locking. I recommend you read Jon Skeet's excellent multi threading guide
  2. You can add the BGW declaratively via the designer, saving yourself the instantiation and event hooking code
ohadsc
I agree but the backgroundworker acts like a message pump in the application and the reason for creating another thread is to free up the UI thread whilst I pre process data before feeding it to the background worker to dispatch. Unfortunately I cannot change the bw.
Parsley
I think you may be confusing the BGW notification mechanism (which is indeed based on the message pump) with the asynchronous invokation which simply boils down to BeginInvoke, which uses the ThreadPool
ohadsc
My point is that you can do all the processing in the BGW DoWork() function, it will not be on the UI thread
ohadsc
Thanks but the above is just pseudo to demonstrate the problem and I cannot actually change the BGW code as its part of an existing application so I have to call it as it is and it works just fine. Until its not called from the UI thread, and unfortunaltely the processing that the UI thread is doing before handing over to the BGW is too much making the UI unresponsive. I need a way to take the load off the UI thread, perform the processing and the call the BGW but this is where the problem is.
Parsley
Then consider creating your own BGW to run the existing code (kind of BGW inside BGW). In Winforms, working with BGW is much easier than working with threads most of the time
ohadsc
just tried calling the BGW from another BGW and it still fails but thanks for the advice +1
Parsley