0

I am about to write an application that gets streaming data from the TCP port, doing some real time calculations on them. All good so far, but the user interface and the marquee progress bar are getting stuck (for irregular, short time periods) when the producer thread is started to do some packaging on the data chunks (see code).

        void Produce()
    {
        try
        {
            while (true)
            {
                foreach (Chunk _chunk in bcPort)
                {
                    if (_ThreadCanceler.IsCancellationRequested) break;
                    Chunk chunk = bcPort.Take();
                    chunk.TimeTracker = new Stopwatch();  
                    chunk.SegmentId = iSegmentId;
                    if (chunk.Channel + 1 == iChannels) iSegmentId++; // last channel, raise segment id.                     
                    iPrevChannel = chunk.Channel;
         //         _ProcessAndJoin.EnqueueTask(chunk, _ThreadCanceler);                       
                    iChunksProduced++;
                    _LogWriter.WriteMessage("Task " + Task.CurrentId.ToString() + "(producer): ADDED_ Chunk[" + chunk.Channel + ":" + chunk.Vals.Count.ToString() + ":" + chunk.SegmentId + "] [" + iChunksProduced + "]. " + bcPort.Count + " for takeaway. Thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
                }
                if (_ThreadCanceler.IsCancellationRequested) break;
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("ForkAndCrate.cs: Produce(): " + ex.ToString());
        }
    }

I did a lot of testing and found out that the access to the BlockingCollection bcPort seems to be the problem. bcPort gets constantly chunks from another data-adder thread which is also supposed not to influence the ui thread. So I don't understand the following:

1.) Why is the GUI getting stuck when I am using different threads for adding and packaging the chunks?

2.) Why is this happening when I am using a BC for storing data? Aren't these thread safe collections for this certain purpose?

By the way: Windows 7 ResourceManager shows 100% CPU usage during streaming, the chunks contain about 2000 float values each, 4 or 5 of them a rushing in per second. I also disabled the Logger but no effect. The consumer and evaluation threads are disabled.

Besides the ui thread, there is only a thread called "ReceiveAndSave" which makes chunks out of incoming float values (see code, Method "Add"). the thread "Producer" is doing some further packaging and enqueues the chunks for the consumer (deactivated).

   public void Add(short iChannel, float fValue)
    {
        try
        {
            _Benchmark.UpdateRec();  // one value received, update benchmark:
            if (!cdBasin[iChannel].Enqueue(fValue))
            {
                Chunk chunk = new Chunk();
                chunk.Vals = cdBasin[iChannel].ToListDeep;
                chunk.Channel = iChannel;
                bcPort.Add(chunk);
                cdBasin.AddOrUpdate(iChannel, new BoundedQueue<float>(iSegmentSizePerChannel), (key, oldValue) => new BoundedQueue<float>(iSegmentSizePerChannel));
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString(), "Stop", MessageBoxButtons.OK, MessageBoxIcon.Stop);
        }
    }

The producer is started with 'myThreads[0] = new Thread(Produce); myThreads[0].Name = "Produce"; myThreads[0].Start();'

pagid
  • 13,559
  • 11
  • 78
  • 104
Rome
  • 432
  • 6
  • 27
  • It's not clear where the code you've posted is running, or what threads you've actually got going on... please clarify your situation. – Jon Skeet May 28 '12 at 16:07
  • the add method seems to be a bit weird but the chunks must have exactly 500 vals each and have to stay connected to their channel, which is not easy to assure by so many data rushing in. besides that, for performance reasons, i dont want to use remove on dictionary or bc, because its very costly, so i am updating instead of removing and adding. but the add method is not the problem, it runs very smooth and fast, as long as the producer does not access the BlockingCollection 'bcPort'. – Rome May 28 '12 at 16:21

1 Answers1

1

It doesn't really get stuck, you are just giving it too much work to do. Which makes it not take care of its low-priority tasks anymore, responding to input and paint notifications. Which indeed makes it look like it is stuck, your user will certainly think so.

The key is to only update the UI at a rate that makes sense to the human eye. Which cannot perceive anything but a blur beyond 25 updates per second. If you push it to as many as a thousand updates per second you'll get the behavior you describe. So collect results and don't invoke/update until enough time has expired. And in general compact the info you display into consumable chunks to give the user meaningful feedback, a list that displays hundreds of new items a second is not useful to anybody.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • thank you. the logfile is only meant as a help to me, to see if things are going on right. for user feedback i have a evaluator which invokes a benchmark of processed chunks to the gui only every second. so my problem is more a cosmetic problem and the marquee progressbar does not seem to be right to display continuous processing. is there an other nice way to display constant progress to the user in such a calculation intensive case (besides my benchmark)? – Rome May 28 '12 at 16:48
  • Anything is possible, a simple counter will do. Your snippet is too opaque to give a specific recommendation. – Hans Passant May 28 '12 at 17:07