How to use real-time priority correctly

My question may not be with regard to real-time processing, but again, maybe.

My application has several threads, which are much more important than the graphical interface, BUT, I want the GUI to be at least useful. I do not want it to be locked at all times, and I want to update the screen, the received processing result, which I perform.

Currently, all of my main elements are isolated in separate threads, and I call a delegate in my GUI to display the results.

My GUI works, but if I change the tabs or minimize / maximize it, as you know, it interferes with my other threads to such an extent that they cannot perform their operations within 0.1 s to which they are bound.

This is what I do to call my delegate:

delegate void FuncDelegate(ResultContainer Result); FuncDelegate DelegatedDisplay= new FuncDelegate(DisplayResults); //then later on Invoke(DelegatedDisplay, Result); 

Most of my critical processes are threads that run in continuous loops, are pulled, and go into various buffers (ArrayLists and regular lists).

One of my critical threads starts every time using:

 Thread mythread = new Thread(new ThreadStart(ProcessResults)); mythread.Start(); 

The reason I decided to do this, instead of having a thread running in a loop, pulling from lists, was because I thought that the reason I was running out of hours was because I have the polling cycle that I worry consumes too many resources (although I use Thread.Sleep (5) every time the polling becomes negative).

Does a new thread start every time I need a parallel process, does it cost me valuable time? Should it be a loop? Are my loops to blame?

Can I pass a thread higher priority than others, or use Thread.Sleep only my option? If I prioritize a higher thread, how can I be sure that other threads can even survive?

Why do simple form events interfere with my other flows? Is there a way to give my GUI thread a designated, less resource? Can I use Thread.Sleep to somehow block Form events if there is not enough time in other threads?

Concluding the answer to all my disappointing questions, is there some kind of thread profiler that I can use to help determine my mess? I tried using the "Managed Stack Explorer", but for some reason this does not always show which threads my application has.

Any help on this would help me a lot.

+4
source share
2 answers

Well here is the start:

 Invoke(DelegatedDisplay, Result); 

This means that you call the background thread until the UI thread actually performs the drawing operation, and then continue. In terms of flow, that is eternity. You can learn asynchronous updates for the user interface:

 BeginInvoke(DelegatedDisplay, Result); 

This is equivalent to the UI thread story, โ€œwhen you have a chance, do this drawing actionโ€ and then continue with the work you do.

You should be aware that this can lead to thread safety issues that did not occur when using Invoke . For example, if the background thread is still modifying the Result while the user interface is trying to draw, you may have unexpected race conditions.

See Control.Invoke vs Control.BeginInvoke

+4
source

Using marshaling methods like Invoke and BeginInvoke to update the user interface is part of the problem. In fact, I rarely use marshaling operations for the interaction of the user interface and the workflow, because it is not so good at solving. Well, to be honest, this can be (and usually) the worst solution in most cases of this kind.

What I usually do is that the workflow publishes its results or advances into the general data structure and has a poll of the user interface stream for it using System.Windows.Forms.Timer (or DispatcherTimer ) on an interval that is configured for the best work for the current situation.

Here's what it might look like.

 public class YourForm : Form { private ConcurrentQueue<ResultContainer> results = new ConcurrentQueue<ResultContainer>(); public UpdateTimer_Tick(object sender, EventArgs args) { // Limit the number of results to be processed on each cycle so that // UI does not stall for too long. int maximumResultsToProcessInThisBatch = 100; ResultContainer result; for (int i = 0; i < maximumResultsToProcessInThisBatch; i++) { if (!results.TryDequeue(out result)) break; UpdateUiControlsHere(result); } } private void WorkerThread() { while (true) { // Do work here. var result = new ResultContainer(); result.Item1 = /* whatever */; result.Item2 = /* whatever */; // Now publish the result. results.Enqueue(result); } } } 

The fact is that people have been programmed to automatically use Invoke or BeginInvoke to update the user interface, that they ignore the best solutions. This has gone so far as these marshaling methods to fit into the sphere of cult cargo programming . I probably sound like a broken record on this topic because I keep copying it all the time. The technique that I used above has the following advantages.

  • It breaks down the tight connection between the user interface and workflows that impose marshaling operations.
  • The worker thread should not wait for a response from the user interface thread, as is the case with Invoke .
  • It is not possible to saturate the message queue of the user interface, as is the case with BeginInvoke .
  • You get more bandwidth for both the user interface and workflows.
  • The user interface thread determines when and how often the user interface thread should be updated.
  • You do not need to mutate your code (and I mean it literally) with Invoke or BeginInvoke .
  • Road marshaling operations.
  • The code looks more elegant.

Starts a new thread every time I need a parallel process cost me valuable time? Should it be a loop? Are my loops to blame?

I would avoid creating flows of perforce. If you can keep the thread in a loop, that would be better.

Can I give a thread a higher priority than others, or is using Thread.Sleep my only option? If I prioritize higher threads, how can I be sure that other threads can even survive?

Giving your work thread a higher priority is likely to help in this case. Thread.Sleep(5) will not sleep for 5 ms. It just doesn't work. By the way, there are some special values โ€‹โ€‹that you can pass to Thread.Sleep .

  • Thread.Sleep (0) prints to any thread with the same or higher priority on any processor.
  • Thread.Sleep (1) gives any thread on any processor.

Why do simple form events interfere with my other flows? Is there a way to give my graphics stream an assigned, lesser amount of Resources? Can I use Thread.Sleep to block Form events if other threads run out of clock time?

This is because you are using Invoke . Avoiding marshaling operations will help significantly, as it separates threads. Do not use Thread.Sleep in the user interface thread. The user interface thread must remain unlocked for it to work correctly. If you are using the solution that I propose above, it is much easier to throttle the UI thread.

+1
source

Source: https://habr.com/ru/post/1415364/


All Articles