Pregunta

Soy un poco nuevo en Java, por lo que aún no he comprendido completamente el concepto de multihilo. Me gustaría crear una clase de PIDController que me permita hacer esto:

ControllerMethods methods = new ControllerMethods()
                            {
                                public long getError(long setpoint)
                                {
                                    //get an input
                                }
                                public void setOutput(long value)
                                {
                                    //do something
                                }
                                public void isComplete(long setpoint)
                                {
                                    return getError() == 0;
                                }
                            };

PIDController motorPID = new PIDController(setpoint, kp, ki, kd, methods);

motorPID.run();
//runs the PID controller to completion (methods.isComplete() == true)

motorPID.run(false);
//starts the PID controller in a separate thread, allowing
//continual monitoring in the current thread

while(motorPID.isRunning())
{
    //do something else
    if(condition1)
        motorPID.pause();
        //pause the PID controller, preventing the integral from increasing
    else if(condition2)
        motorPID.stop();
}

He resuelto cómo calcular los argoritmos PID estándar, pero no puedo encontrar la forma de proporcionar la funcionalidad asíncrona.

¿Alguien puede decirme cómo puedo lograr una API similar?

¿Fue útil?

Solución

Ya implementó un método run () para PIDController , por lo que también debe implementar la interfaz Runnable :

class PIDController implements Runnable {
    ....
}

Ahora puede iniciar su controlador PID asíncrono llamando a:

pidControllerThread = new Thread( pidController );
pidControllerThread.start();

Para la sincronización (si es necesario), debe mirar el sol guía de concurrencia .

Otros consejos

Por mucho, el mejor mecanismo para unir hilos a cualquier cosa es separar el objeto que hace el trabajo del objeto que es el hilo. La interfaz Runnable puede ser atractiva, ya que permite a las personas pasar el objeto a un constructor de Thread o Ejecutor y ejecutarlo. Sin embargo, si tiene requisitos de administración de ciclo de vida para su objeto que están fuera de la ejecución de "quot hasta su finalización", como la pausa, entonces encontrará que es más apropiado en la mayoría de los casos, administrar el Thread dentro de su objeto para que sepa cuál el hilo se está ejecutando (sí, puede establecer un objeto de instancia en Thread.currentThread () en la entrada para ejecutar, pero ...).

Entonces, creo que lo que tienes es un buen comienzo. Debe agregar el uso de algún bloqueo para ayudarse a administrar pause () y otro control de subprocesos.

    public class PIDController {
        private final Object myLock = new Object();
        private final ControllerMethods ctrl;
        private volatile Thread thread;
        private volatile Runner runner;
        private int pidInterval = 700;
        private final double setPoint, kp, ki, kd;

        public PIDController( double setPoint, double kp, double ki, double kd, ControllerMethods inst ) {
            this.ctrl = inst;
            this.setPoint = setPoint;
            this.kp = kp;
            this.ki = ki;
            this.kd = kd;
        }

        public void pause() {
            synchronized( myLock ) {
                if( runner.paused ) {
                    throw new IllegalOperationException(this+": already paused");
                }
                runner.paused = true;
            }
        }

        public void resume() {
            synchronized( myLock ) {
                if( !runner.paused ) {
                    throw new IllegalOperationException(this+": already resumed");
                }
                runner.paused = false;
            }
        }

        public bool isRunning() {
            return running;
        }

        public void start() {
            if( thread != null ) {
                throw new IllegalOperationException( this+": already running");
            }
            myThread = new Thread( runner = new Runner() );
            myThread.start();
        }

        public void stop() {
            if( runner == null ) {
                throw new IllegalOperationException( this+": PID is not running");
            }
            runner.running = false;
            if( runner.paused )
                resume();
            runner = null;
        }


        // It is important, anytime that you implement a stoppable Runnable, that
        // you include the "running" flag as a member of an innner instance class like
        // this so that when you ask this instance to stop, you can immediately restart
        // another instance and not have the two threads observing the same "running" flag
        private class Runner implements Runnable {
            volatile bool running = false, bool paused;
            public void run() {
                running = true;
                while( running ) {
                    // do this at the top of the loop so that a wake from
                    // pause will check running, before recomputing.
                    reComputePID();

                    // Use the double check idiom to 
                    if( paused ) {
                        synchronized( myLock ) {
                            while( paused ) {
                                myLock.wait();
                            }
                        }
                    }
                    Thread.sleep( pidInterval );
                }
            }
        }

        public void reComputePID() {
            ...
        }
    }

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top