How to control a slow process while updating GUI?

M

Thread Starter

Mehdi

Hi everybody.

I'm using a PC with ADAM 500 series to control the process of an autoclave. It is a slow process, also ADAM modules are slow. But I need to update the user interface somehow rapidly. Now, it looks like discontinous: the user interface is updated every 5 seconds. also it responds to key strikes very slowly. I want to optimize it and make it faster.

Simply I have two questions:
1 - What is the classic way of controlling systems with PCs? I know PLCs have their rules: they first read all inputs and outputs and then do the process, then again...
But how PCs do the controlling? Is it a good practice to implement PLC-like controlling methods? or there are other ways to do this? I would appreciate any help or any reference/web page/...

2 - Is it just ADAM modules that put delay in system? their rate is now 10Samples/second! very slow! do you suggest PCI-based I/O modules? what are their problems?

Thank you very much in forward, I hope this will be a hot topic, because I do want to learn!

Regards,
Mehdi
 
R

Rainer Lehrig

If you have to do 2 things at the same time (GUI + control), you have to use Threads.

The normal program handles your GUI application. For the control application, you start a new Thread that runs in parallel to your main application.

The Thread does the following:
forever
read inputs
processes 1 step
write outputs

Your main application may communicate with the Thread using global variables.

On a posix system you create a thread with:
pthread_create(...);

On windows you create a thread with:
CreateThread(...);
 
R

Robert Scott

PC programs in automation can take a wide variety of forms, some of which are better than others. It is the responsibility of the programmer to design a good program. The programmer is not restricted to a scan loop paradigm, like the kind used in PLCs.

From your description, it sounds like your PC program has integrated the process control functions into the same thread that controls the GUI. A better way is to let the GUI thread control only the GUI. The process control functions can be handled by a separate thread. A well-designed process control thread spends most of its time suspended so that other threads, including the GUI thread, are given all the CPU time they need. This allows the GUI to exhibit fast response to keystrokes and display updates.

Of course there must be some interaction between the process control functions and the GUI. If these interactions are handled properly, they will not affect GUI responsiveness. For example, suppose one of the timer-based GUI functions is to display the latest process control value. If, at the time of the timer hit, the process control value has not been determined by the process control thread, then the GUI thread should not wait for it. The GUI thread should simply skip the display update on such timer hits.

Robert Scott
Real-Time Specialties
Embedded Systems Consulting
 
PCs should be programmed based upon events rather than a fixed sequence of instructions. Use the multitasking capability of the OS to do multipul tasks at the same time. Only when the ADAM is ready then read that data - but don't hold up other tasks while you wait for some function to finish. That was the old way to program (the PLC way).

Also use plenty of 'Doevents' or 'GetInputState' (in the user32 API) to allow the PC to react to keyboard, mouse, paint, and other OS functions immediatly without waiting for some slow function to complete.

Warren
http://www.pc-pid.com
 
Hi dear friends,
Thank you very much for your fast and helpful comments.

Actually I have used Threads in my program, but the problem still exists:
There are some situations in which the process continues only after a specific signal reaches a pre-determined value, for example a digital signal changes state from 0 to 1, or an analog signal reaches 16 mA. Now, I have written some loops (While loops) which wait until the condition is set. for example, suppose I'm waiting for a digital signal named E1 to change state from 0 to 1, I have written something like this:

While (E1 == 0)
{
ReadDigitalSignal(E1_Address);
}

These loops in the program cause the GUI to work discontinously: it updates, then the process thread should acquire data, but it needs time, so the next time GUI thread updates, it is 5seconds later, some stop-and-go action in the GUI update manner.

My specific problem is how to improve the performance? how to improve the GUI? how to avoid these loops?

Thank you in advance...
Mehdi
 
R

Robert Scott

I would advise against that. Such measures are necessary only if you insist on bundling everying into the one main GUI thread. It is much cleaner to leave the main GUI thread free of all process control functions and set up a separate thread to do the process control stuff. The PC will react immediately through the main GUI thread, as long as the process control thread is well-behaved and does not hog the CPU. Even if it does misbehave, the Windows time-sharing will still let the GUI thread run occasionally so that the PC will be responsive. Also segregating the functions in this way will make the code much easier to debug.

Robert Scott
Real-Time Specialties
Embedded Systems Consulting
 
R

Robert Scott

Yes, of course. This is another bad idea. It is called spin-waiting, and it has no place in any well-designed multi-tasking operating system application. Instead, if you have something that must be polled, then decide how frequently you really need to poll it, and then limit your polling to that frequency. For example, if the E1 state mentioned above only needs to be checked every 200 msec, then insert into the loop a Sleep(200). This will surrender the CPU to other waiting tasks, including the GUI. Even a Sleep(0) will help a little.

Robert Scott
Real-Time Specialties
 
M

Michael Griffin

I am not perhaps as much of an expert in this field as some others you will find on this list, however in general I would guess that your control thread is hogging the CPU. This can be particularly a problem if the I/O library calls are not interruptable. Your program may be spending most of its time waiting for the I/O calls to complete before any of the threads in that process are allowed to continue.

You haven't stated what operating system you are using, but in general you have several options. If your operating system supports it, you may wish to simply adjust the amount of CPU time the control thread is allowed to have. You may also wish to look into the difference between threads and processes as these may differ in that respect.

The other method is to insert "sleep" (or whatever your library equivalent may be) statements in your loops to force the thread to pass control back to the scheduler. To use your example:

While (E1 == 0) { ReadDigitalSignal(E1_Address); sleep(somevalue); }

In the above example, the thread will pass control back to the scheduler once each loop iteration. You would probably want to write the logic in a manner such that "sleep" only gets called if the loop exit conditions are not met.

Of the two methods above, the first one (adjusting the thread priorities) is the more elegant, and is also the more reliable as it doesn't leave you vulnerable to forgetting a "sleep" in one of your loops.

However, again it depends upon whether or not your operating system will block all threads in the same process until an I/O call returns. If the process containing your threads spends 99% of its time in the "ReadDigitalSignal" call, the scheduler cannot do its job properly if it is not allowed to de-schedule a thread before "ReadDigitalSignal" has returned. The idea of the "sleep" statements is to force the thread to give up the CPU before it tries another (probably pointless) "ReadDigitalSignal" call (you are providing an explicit pre-emption point). You will however have to take the thread priorities into account to ensure that the GUI thread gets a crack at things before the control thread is rescheduled to make another try at "ReadDigitalSignal".

A third alternative may be possible if your hardware, library, and OS allow your I/O devices to generate interrupts when a condition is met. In this case, you would set up the devices to generate an interrupt to wake up the control thread when the input changes state, or when an analogue value reaches a trigger threshold. Then your control thread would go to sleep while waiting for the interrupt. This method sounds simple in principle, but can be difficult to implement in practice when taking faults and exceptions into account.


On December 17, 2004 17:26, Mehdi wrote: <clip>
> Actually I have used Threads in my program, but the problem still exists:
> There are some situations in which the process continues only after a
> specific signal reaches a pre-determined value, for example a digital
> signal changes state from 0 to 1, or an analog signal reaches 16 mA. Now, I
> have written some loops (While loops) which wait until the condition is
> set. for example, suppose I'm waiting for a digital signal named E1 to
> change state from 0 to 1, I have written something like this:
>
> While (E1 == 0)
> {
> ReadDigitalSignal(E1_Address);
> }
>
> These loops in the program cause the GUI to work discontinously: it
> updates, then the process thread should acquire data, but it needs time, so
> the next time GUI thread updates, it is 5seconds later, some stop-and-go
> action in the GUI update manner.
>
> My specific problem is how to improve the performance? how to improve the
> GUI? how to avoid these loops?
<clip>

( Complete thread: http://www.control.com/1026204175/index_html )
 
Dear all,
thank you very much for your good comments, especially Robert!

I have nother question: does it make difference to put the controlling process in the main thread and the GUI in another one, and vice versa? I mean, is it a good practice to put the controlling process in the main thread?

Thank you in forward again,
Mehdi
 
R
When a Windows program starts up, it is running in one thread. I suppose you could call it the "main" thread. What makes it the GUI thread is that it enters a message loop handling messages for the main window. I suppose the main thread could create a second thread, and then that second thread could create the application windows and enter a GUI message loop, and the first thread could engage in process control. But why would you want to do that? It is much simpler to stick with tradition and let the main thread handle the GUI. Sometimes you may even need to create several worker thread to handle control functions. One very important detail is that you make sure that the main thread has a way of telling the worker threads when they should exit. This can only be done if the worker thread is periodically checking for some signal from the main thread. Otherwise your program will have a hard time quiting.

Robert Scott
Real-Time Specialties
Embedded Systems Consulting
 
Top