2

I'm trying to learn threading on C# but have got a bit stuck on how to handle properties.

Take for example my class NavigateIE which can only carry out a single action at a time. I thought if I had a property busy then I would know if the instance was busy outside the class.

class NavigateIE
{
    public bool busy;

    public void IEAction(string action)
    {
        busy = true;

        var th = new Thread(() =>
                {
                    try
                    {
                        //Do stuff

                    }
                    catch(Exception ex)
                    {
                        //report Exception
                    }
                    finally
                    {
                        busy = false;
                    }
                });
        th.SetApartmentState(ApartmentState.STA);
        th.Start();

    }

}

However, as busy = false; is only ever called inside the thread then this doesn't work as navigateIE.busy is always true.

class MainElsewhere
{
    private NavigateIE navigateIE = new NavigateIE();

    private void Main()
    {
     if (!navigateIE.busy)
     {
      //navigateIE.busy always == true
     }
    }

}

I have 2 questions:

1) How do I set up the property so it's threadsafe and busy = false; is seen outside the class?

2) Is there a better way to do this?

Edit: Essentially NavigateIE is a class to handle a single instance of IE using Watin. I can only call a method in NavigateIE if there are no other methods running otherwsie a previous action has not completed. NavigateIE is called from a main method that is on a timer tick, hence why I need to check if the class is busy.

navigateIE.busy == false the first time but after the thread sets it back to false the main method still sees navigateIE.busy == true.

  • 2
    Your `busy` is **not** a property, it's a member field. – Ondrej Tucny Nov 15 '13 at 22:48
  • "2) Is there a better way to do this?" Hard to say, because I have no idea what you're trying to do. Can you explain *in words* what you're trying to accomplish? – Jim Mischel Nov 15 '13 at 22:50
  • 1
    Is it always true because you are checking isBusy too early? Do you want to block until it completes? Take a quick look here as well http://msdn.microsoft.com/en-us/library/System.Threading.Interlocked(v=vs.110).aspx Must wrap the busy field in a property in any case btw. – atomaras Nov 15 '13 at 22:52
  • @OndrejTucny - your right, my terminology may be wrong. @ Jim - I've updated my Q to address what I'm attempting. –  Nov 15 '13 at 22:53
  • I think the question is still not totally clear -- consider providing a concise, complete example to illustrate the problem. (http://sscce.org/) – McGarnagle Nov 15 '13 at 23:03

3 Answers3

3

You are doing this fundamentally wrong. Yes, busy is pretty likely to be true, that thread will start running quickly on a modern multi-core processor. No actual guarantee, it is merely very common. Exactly when it turns back to false is highly unpredictable as well, depends what the thread does. Including never, a bool is not a synchronization primitive.

It is not clear to me what you are trying to achieve, but you don't actually need to use a busy flag at all. IE is an apartment-threaded COM object, it already automatically marshals the call to the STA thread that owns the object. Calling its Navigate() method from another thread is fine, no extra code is required to help. If you need a busy flag to indicate that the browser is working on a command then you'll need a flag that you set to true when you actually start navigating instead of when you start the thread. Leverage the code in this answer, perhaps.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
2

I started to write an answer, but there are just a lot of variables here. (you should be locking, but really signalling might be a better solution, etc). I really think that rather than throwing a code snippet at you, a better answer would be do direct you to do a little more digging on .net threading.

Here's an ebook that might be helpful for you: http://www.albahari.com/threading/

JMarsch
  • 21,484
  • 15
  • 77
  • 125
2
  1. How do I set up the property so [..] busy = false; is seen outside the class?

    Your example doesn't work because busy needs to be marked volatile

  2. Is there a better way to do this?

    It sounds like all calls within NavigateIE always need to be serialized. If that's true, I would just put a lock statement in each thread-call

    public object mutex = new object();
    
    public void IEAction(string action)
    {
         var th = new Thread(() =>
            {
                lock(mutex)
                {
                    //Serialzed code goes here
                }
            });
    
         //etc.
    }
    

    Also, note that you rarely want to actually create your own Thread instance - you should either be using a BackgroundWorker, obtaining a thread from the ThreadPool, or using the new Tasks Parallel Library (TPL).

    If you're unsure, the TPL is usually the best place to start.

Community
  • 1
  • 1
BlueRaja - Danny Pflughoeft
  • 84,206
  • 33
  • 197
  • 283