Click here to Skip to main content
11,477,625 members (74,451 online)
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C# WPF
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:

    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:

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 27-Sep-12 5:00am

1 solution

Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

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:

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.

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.
  Permalink  
v5
Comments
NeonMika at 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 at 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 at 27-Sep-12 10:33am
   
Solution updated :-D
NeonMika at 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 at 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)
NeonMika at 27-Sep-12 11:01am
   
You are right. But for example, my MixUpdater needs to use other classes like my MusicDownloadConnection, SortType, etc.. I always have to use them together if I need them in another application.
So the main thing I should keep in mind is that I should keep the "logic" decoupled from my "view", am I right in this? :)
I will have a detailed look on SOLID and I have 5 years of univerity comming up to my, I hope my skills will get better and better.
Stephen Hewison at 28-Sep-12 3:00am
   
In simple terms yes, decoupling the logic from the view is a good idea. Traditionally software application are developed in 3 layers to enable them to be reused. Data access layer (DAL), Business logic layer (BLL) and the User interface layer (UIL). When you progress to building larger systems you'll find this approach useful as often in business systems you have multiple applications/processes need to consume to the same data/logic. If you want some good reading to give you insight into other design practices I'd suggest reading the following... Service Oriented Programming, Aspect Oriented Programming, Domain Driven Design Practices, Test Driven Development Practices, SOLID principles. Also an understanding of practices around inheritance, polymorphism, abstraction, interfaces. Design patterns as well, the more design patterns you understand the more tools you'll have in to tool bag to solve logic problems as they present.
Stephen Hewison at 27-Sep-12 10:36am
   
The logic you apply to which record you get is up to you. Thats the bit you decide for yourself and write in where the comment is in the MixUpdater.
Marcus Kramer at 27-Sep-12 11:10am
   
+5. Nicely answered.
RaisKazi at 27-Sep-12 11:11am
   
Good Answer!5ed.

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

  Print Answers RSS
0 Sergey Alexandrovich Kryukov 274
1 Richard Deeming 245
2 _duDE_ 165
3 Tomas Takac 150
4 Sascha Lefèvre 145
0 Sergey Alexandrovich Kryukov 7,675
1 OriginalGriff 7,246
2 Sascha Lefèvre 3,034
3 Maciej Los 2,491
4 Richard Deeming 2,305


Advertise | Privacy | Mobile
Web04 | 2.8.150520.1 | Last Updated 27 Sep 2012
Copyright © CodeProject, 1999-2015
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100