1

I'm trying to build a button that displays a loading circle and loads some data in a C# application.

I have a boolean value called Loading that tracks the state of the current data that is being loaded.

I have a delegate called LoadHandler that returns a boolean value based on whether the loading is complete or not, I also have an event that can be subscribed to in a separate class that takes the LoadHandler signature and handles the actual loading.

I have a private Load() function that gets called when an event handler for input is called in the base class, this is called on a new Thread.

Here's the code for the LoadEntry class (Keep in mind this is just a button that displays a loading circle when hit, and delegates loading to a separate class)

public class LoadingEntry : ButtonEntry
{
    private readonly object objLock = new object(); 

    /// <summary>
    /// The loading circle texutre
    /// </summary>
    Texture2D loadingReticle; 

    /// <summary>
    /// Tracks the rotation of the loading reticle.
    /// </summary>
    float loadingRotation;

    /// <summary>
    /// Tells whether we are loading or not
    /// </summary>
    public bool Loading { get; private set; } 

    public LoadingEntry(string buttonText)
        : base(buttonText)
    {

    }

    /// <summary>
    /// Handler that will return true when loading information is complete
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    /// <returns>True if loading is complete</returns>
    public delegate bool LoadHandler(object sender, EventArgs e); 

    /// <summary>
    /// The LoadHandler event that should be subscribed to in a menu class 
    /// </summary>
    public event LoadHandler onLoad;

    private void Load()
    {
        if (onLoad != null)
        {
            lock (objLock)
            {
                Loading = true;
                while (true)
                {
                    Loading = onLoad(this, EventArgs.Empty);
                    if (!Loading)
                        break;
                }
            }
        }
    }

    protected internal override void OnSelectEntry(PlayerIndex playerIndex)
    {
        Thread t = new Thread(new ThreadStart(Load));
        t.Start(); 
        base.OnSelectEntry(playerIndex);
    }

    public override void Draw(MenuScreen screen, bool isSelected, GameTime gameTime, bool fade)
    {
        if (Loading)
        {
            loadingReticle = screen.ScreenManager.LoadingReticle; 

            Vector2 origin = new Vector2(loadingReticle.Width / 2, loadingReticle.Height / 2); 
            loadingRotation += 0.01f;

            screen.ScreenManager.SpriteBatch.Draw(loadingReticle, position, null, Color.White, loadingRotation, origin, 1f, SpriteEffects.None, 1f); 
        }
        else base.Draw(screen, isSelected, gameTime, fade);
    }

The base class ButtonEntry shouldn't be important.

And here's what is subscribed to onLoad in another class: (just for practice, this is where actual loading code would go)

    int sampleTics = 0; 
    bool sampleLoad_onLoad(object sender, System.EventArgs e)
    {
        sampleTics++;
        if (sampleTics < 1000)
            return true;

        return false; 
    }

My question is am I using mulit-threading properly? The code doesn't even display the circle, I haven't done much testing yet because i'm going to bed. Is the lock necessary in this situation? Is there a better way to do this that i'm not seeing?

Josh Siegl
  • 735
  • 1
  • 9
  • 16

2 Answers2

1

bool is thread safe according to the documentation. See this post for a similar question. As suggested by the post you also need to declare your boolean variable volatile so that its value is not cached. You can't declare properties volatile so you'll need to add a backing property and declare that volatile.

Community
  • 1
  • 1
NeddySpaghetti
  • 13,187
  • 5
  • 32
  • 61
  • This is good information and something that I left out but as it turns out I needed to call `Thread.Sleep(1);` so that it could exit the loop, it makes loading slightly longer but it did the trick – Josh Siegl May 19 '14 at 03:07
0

It turns out that I needed to call Thread.Sleep(1); in order to see the results. Here's the complete code:

private void Load()
    {
        if (onLoad != null)
        {
            loading = true;
            while (true)
            {
                loading = onLoad(this, EventArgs.Empty);
                if (!loading)
                    break;

                Thread.Sleep(1); 
            }
        }
    }
Josh Siegl
  • 735
  • 1
  • 9
  • 16