2

im new here and always find helpful threads here, but not in this case. I'm having an issue with my program using threads. In special, my thread is doing some image pattern in the backround and everything seems to be fine. It also works an undefined time (sometimes 15 s, sometimes minutes) without any exception or freeze or whatever. But then my GUI freezes, not my whole GUI, just the GUI parts updated from the thread. Two other pictureboxes are working fine(streaming a video), but the rest isnt working. Trying to stop the thread where it is, works, but starting it from there makes my program collapse. There arn't eny exceptions thrown. Every GUI element is updated via Invoke() if necessary. I only work on a copy of the Picture to avoid any lockmodes or anything else. Also i try to let the UI doing what it needs to do (DoEvents()) Some ideas? Code:

namespace My.Name.Space
{
    public class MyThread : MyThreadBase
    {

         public MyThread ( getting object s from the form for updating UI elements)
         {
              //referencing objects
              Stopwatch.Start();
         }


       //example Method for UI updating
       private void UpdateRobot1Box(int angle, int x, int y)   
       {
           if (_rob1.InvokeRequired)
           {
               _rob1.Invoke(new Action(() => _rob1.Clear()));
               _rob1.Invoke(new Action(() => _rob1.Text = angle.ToString() + "°, X:" + x.ToString() + ", Y:" + y.ToString()));
           }
           else
           {
               _rob1.Clear();
               _rob1.Text = angle.ToString() + "°, X:" + x.ToString() + ", Y:" + y.ToString();
           }
       }

          protected override void Loop(CancellationToken token)
          {
               while(!token.IsCancellationRequested)
               {
                     if( PictureBox != null && Stopwatch.ElapsedMilliseconds >= tick)
                     {
                          //DoWork
                          Application.DoEvents();
                     }
                     else
                     {
                          Thread.Sleep(1);
                     }
                 }
             }
         }
     }
 }

Edit 1:

MyThreadBase:

namespace My.Name.Space
{
    public abstract class MyThreadBase : DisposableBase//just some simple gc stuff
    {
        private CancellationTokenSource _cancellationTokenSource;

        public bool IsAlive
        {
            get { return _cancellationTokenSource != null; }
        }

        public event Action<Object, Exception> UnhandledException;

        public void Start()
        {
            if (_cancellationTokenSource != null)
                return;
            lock (this)
            {
                if (_cancellationTokenSource != null)
                    return;

                _cancellationTokenSource = new CancellationTokenSource();

                var thread = new Thread(RunLoop) {Name = GetType().Name};
                thread.Start();
            }
        }

        public void Stop()
        {
            if (_cancellationTokenSource == null)
                return;
            lock (this)
            {
                if (_cancellationTokenSource == null)
                    return;

                _cancellationTokenSource.Cancel();
            }
        }

        public void Join()
        {
            while (IsAlive) Thread.Sleep(1);
        }

        private void RunLoop()
        {
            try
            {
                CancellationToken token = _cancellationTokenSource.Token;
                Loop(token);
            }
            catch (OperationCanceledException)
            {
                throw;
            }
            catch (Exception exception)
            {
                OnException(exception);
            }
            finally
            {
                lock (this)
                {
                    CancellationTokenSource cancellationTokenSource = _cancellationTokenSource;
                    _cancellationTokenSource = null;
                    cancellationTokenSource.Dispose();
                }
            }
        }

        protected abstract void Loop(CancellationToken token);

        protected virtual void OnException(Exception exception)
        {
            Trace.TraceError("{0} - Exception: {1}", GetType(), exception.Message);
            Trace.TraceError(exception.StackTrace);

            OnUnhandledException(exception);
        }

        protected virtual void OnUnhandledException(Exception exception)
        {
            if (UnhandledException != null)
                UnhandledException(this, exception);
        }

        protected override void DisposeOverride()
        {
            Stop();
        }
    }

The UpdateRobot1Box is called in a switch-case construct within the thread. I got a little for-squence where I go through my list of own created objects to decide what to write in my textbox.

Ondrej Janacek
  • 12,486
  • 14
  • 59
  • 93
Retnuoc
  • 45
  • 3
  • Thread.Sleep probably isn't going to help anything – Dustin Davis Mar 06 '14 at 20:02
  • I think more of the code needs to be posted. What's `MyThreadBase`, and how is `UpdateRobot1Box` called? – Matt Sieker Mar 06 '14 at 20:09
  • @DustinDavis Doing `Thread.Sleep(1)` allows the thread to not constantly max the CPU/Core when in a `while` loop. Just 1 millisecond helps quite a bit. – TyCobb Mar 06 '14 at 20:09
  • 3
    Sleep(1), (pointless, gets rounded down to 0), and 'Application.DoEvents()', (especially from a non-GUI thread). You're doomed. – Martin James Mar 06 '14 at 20:19
  • Put another way, get rid of Application.DoEvents and replace the polling Sleep(1) loops with sane inter-thread signaling. – Martin James Mar 06 '14 at 20:29
  • 1
    the use of such primitives (Thread class) for asynchronous programming should be avoided, you should look at using the TPL (Task) or Rx (Reactive Extensions). Also the big issue for me is the use Application.DoEvents to keep the UI responsive - this should be avoided and is the sign of a code smell. – AwkwardCoder Mar 06 '14 at 20:33
  • possible duplicate of [Unseen bug, application stucks](http://stackoverflow.com/questions/21060270/unseen-bug-application-stucks) – Hans Passant Mar 06 '14 at 20:57
  • @HansPassant Unseen bug, application sucks – Martin James Mar 07 '14 at 00:17
  • Nope, I clear all Textboxes before I rewrite them. And I also only update them 4 times a second, at maximum rate. And besides that, not my FULL UI ist frozen, just the element which are updated from the MyThread. – Retnuoc Mar 07 '14 at 08:19
  • Welcome to Stack Overflow! Please, do not include information about a language used in a question title unless it wouldn't make sense without it. Tags serve this purpose. – Ondrej Janacek Mar 07 '14 at 08:20
  • Sleep(1) is valid technique. ignore 'maitres'.. Application.DoEvents is redundant. you simply need a profiler to find there does it freeze. I am sure this will make the problem obvious.. good luck – Boppity Bop Mar 12 '14 at 18:45
  • Instead of using Sleeps and Application.DoEvents to prevent killing the CPU, you could use some kind of conditional variable, which sleeps until it is signaled. This questions describes it nicely: http://stackoverflow.com/questions/15657637/condition-variables-c-net These kind of problems are hard to find, the best chance you have in my opinion is to first fix the fundamental threading mistakes in your application. – Swen Kooij Mar 29 '14 at 14:36

1 Answers1

0

Create a method in main form class to perform the UI update actions:

private void AsyncFormUpdate(Action action)
{
        if (this.InvokeRequired)
        {
            this.Invoke(action, null);
        }
        else
        {
            action();
        }
}

Having that in proper place you are sure that InvokeRequired acts properly, well, and the code is better encapsulated.

Next be simple. Use the asynchronously invoked delegate with feedback to report angle and coordinates changes to UI, where you'll actually call the AsyncFormUpdate method. A good example is shown here:

http://www.csharp-examples.net/asynchronous-method-progress/

There they update the progress, where as you'll update the angle and X/Y coordinates.

Andrew
  • 3,648
  • 1
  • 15
  • 29