Click here to Skip to main content
15,879,613 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hello there!
I think I need your help again. This time it's about threading.
I have my GUI starting my child thread. And the thread starts without problems *yay*
But when I want to call "Stop" or "GoOn", i get something like a deadlock.
Here is my code running in the thread:

C#
public class MixUpdater
{
    private volatile bool MixUpdaterShouldStop = false;
    public bool MixUpdaterStopped { get; private set; }
    volatile object locker = new object( );
    private bool MixerUpdaterGoOn = false;

    public void UpdateMixes(object o)
    {

        //varible declaration etc.

        for ( int i = 1; i <= max; i++ )
        {
            resp = eightTracksConnection.GetMixes(null, genres, 25, sortType, i);

            Debug.WriteLine("Baby says " + Thread.CurrentThread.ManagedThreadId);

            if ( i == 1 )
                max = resp.TotalPages;
            else
            {
                while ( !MixerUpdaterGoOn )
                {
                    if ( MixUpdaterShouldStop )
                        break;
                    Thread.Sleep(10);
                }
            }

            foreach ( Mix m in resp.Mixes )
            {
                dispatcher.Invoke((Action)( ( ) => { Mixes.Add(m); } ), null);
            }

            MixerUpdaterGoOn = false;
        }

        MixUpdaterStopped = true;

    }

    public void RequestStop( )
    {
        MixUpdaterShouldStop = true;
    }

    public void LoadMore( )
    {
        MixerUpdaterGoOn = true;
    }
}


To stop it (at least I try) I use the following code:

C#
if ( MixListUpdaterThread != null )
{
  MixListUpdater.RequestStop( );
  while ( !MixListUpdater.MixUpdaterStopped )
    Thread.Sleep(10);
}


Also the "LoadMore"-Method doesn't work.

I think it is because of the "Thread.Sleep"s, but I cant figure it out.
I also don't know if I should use lock() and where.

I hope you can help me.

Thanks, Markus
Posted

1 solution

You should probably take a look at the Monitor class.

System.Threading.Monitor

Using Invoke performs a thread synchronisation and I normally only use it to allow background threads to update UI elements.

I normally use a code sample similar to this when I have multiple threads access objects in the background:

C#
public class MixCollection()
{

  public delegate void MixAdded(Mix mix);
  public event MixAdded OnMixAdded;

  private List<Mix> _theList = new List<Mix>();

  public void Add(Mix item)
  {
    bool complete = false;
    while(!complete)
    {
      if(System.Threading.Monitor.TryEnter(_theList, 100))
      {
        try
        {
          complete = true;
          _theList.Add(item);
          if(OnMixAdded != null)
            OnMixAdded(item);
        }
        finally
        {
          System.Threading.Monitor.Exit(_theList);
        }
      }
      else
        System.Threading.Thread.Sleep(100);
    }
  }

}

public class MixUpdater()
{

  private Thread _bgThread;
  private MixCollection _mixes;

  public MixUpdater(MixCollection mixes)
  {
    _mixes = mixes;
    Start();
  }

  private bool _stop = false;

  public void Stop() { _stop = true; }
  public void Start()
  {
    if(_stop)
    {
      _bgThread = new Thread(new ThreadStart(Work));
      _bgThread.Start();
    }
  }

  private void Work()
  {
    while(!_stop)
    {
      //do your mix check here adding new items doing the following where you get a new mix
      _mixes.Add(mix);
      
      Thread.Sleep(1000);
    }
  }

}


Then in your UI:

Note although back in your UI class, the thread bubbling the event is still a background thread and as such you need to invoke to update your UI.

C#
public class MyForm : Form
{

  MixCollection _mixes;
  MixUpdater _mixUpdater;

  public MyForm()
  {
    _mixes = new MixCollection();
    _mixes.OnMixAdded += new MixCollection.MixAdd(OnMixAdded);
    _mixUpdater = new MixUpdater(_mixes);
  }

  public void OnMixAdded(Mix mix)
  {
    ListBox.dispatcher.Invoke((Action)( ( ) => { ListBox.Items.Add(mix); } ), null);
  }

}


I've typed all this off the top of my head, so I'm sorry if it's not quite right in your project, but you should get the general idea.
 
Share this answer
 
v5
Comments
NeonMika 27-Sep-12 10:18am    
Mixes is the ObserveableCollection which should be updated from the background thread. The dispatcher used in the background class is the ListBox's dispatcher.

The threads work is to download 25 objects and add it to my list. then it should go to sleep. And I want to have to possibility to say "Load 25 more" or to say "Stop completly".
Stephen Hewison 27-Sep-12 10:21am    
If you've got a collection which is being managed by multiple threads. I'd definitely put the thread safe handling into the collection. Give me a few minutes and I'll try and update with a more complete code sample.
Stephen Hewison 27-Sep-12 10:33am    
Solution updated :-D
NeonMika 27-Sep-12 10:44am    
I really really appreciate your solution, thanks. Now I understand you way. :)
But this seems pretty much code to me for just updating one of my objects. I need a MixesList etc.

But my code is now working when I add a volatile to my MixUpdaterGoOn. If I have time I will I probably change my code to yours. Thanks! :)
Stephen Hewison 27-Sep-12 10:47am    
It is, but the way I've written it allows the MixCollection and MixUpdater to become a programming component which can be used by any application or interface. Your approach irreversibly links the classes to your UI. When thinking about your application design you should consider best practices. Take a look at the SOLID principles, if you learn then and follow them you're coding standards will vastly improve. http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900