2011-11-03 10 views
9

Tengo un hilo que está procesando. Me gustaría poder detener este hilo durante la ejecución, de alguna manera guardar su posición (y el estado de los objetos en los que está operando), y luego continuar desde esa ubicación en una fecha posterior (por lo tanto, después de que mi computadora se haya reiniciado).¿Cómo hago una pausa durante la ejecución, guardo el estado y continúo desde el mismo punto más adelante?

En C# esto no es posible ¿no? Y si no, ¿cuál es el diseño adecuado para lograr esta funcionalidad?

Así que mi deseo original era tener algo así como

class Foo : Task { 
    void override Execute(){ 
     //example task 
     while(someCondition){ 
     ...do stuff... 
     } 
    } 
} 

y ser capaz de hacer una pausa/guardar en cualquier punto dentro de esa función. Cuando la función finaliza, todos saben que está completa. Como alternativa, tal vez esta es la mejor manera de hacerlo

class Foo : Task { 


    void override Execute(State previousState){ 
     //set someCondition, other stuff 
     //IsPaused = false; 
     previousState.setUpStuff(); 

     //example task 
     while(someCondition){ 
      ...do stuff... 
      if(base.IsPauseRequested){ 
       base.UpdateState(); //this would be a bit different but just to get the idea 
       base.IsPaused = true; 
       return; 
      } 
     } 

     base.RaiseNotifyTaskComplete(); 
    } 

} 

Así que el primer caso es mucho más simple para otras personas que necesitan para heredar mi clase base, ya que sólo tienen que implementar la función Ejecutar. Sin embargo, en el segundo caso, deben considerar el estado anterior y también administrar dónde existen buenos puntos de pausa. ¿Hay una mejor manera de hacer esto?

Respuesta

4

Lo que desea puede lograrse mediante una máquina de estado serializable. Básicamente, cambia las variables locales en campos de una clase y agrega un campo que mantiene el estado: la posición en el código del método original. Esta clase será [Serializable] y tendrá un método como MoveNext(), que hace un trabajo y regresa. Cuando trabaja, llama a este método en un bucle. Cuando desee detenerse, espere hasta que finalice la llamada actual, salga del ciclo y serialice la máquina de estado en el disco.

Según la complejidad del método original y la frecuencia con la que desea "punto de control" (cuando regresa el método MoveNext() y puede elegir continuar o no), la máquina de estado podría ser tan simple como tener solo un estado o bastante complicado

El compilador de C# realiza una transformación muy similar cuando compila bloques de iteradores (y métodos de C# 5 async). Pero no es para este propósito y no marca la clase generada [Serializable], así que no creo que puedas usarla. Aunque leer algunos artículos sobre cómo se realiza esta transformación en realidad podría ayudarlo a hacer lo mismo.

0

No puedo responder por C#, pero en general esta pregunta se llama Persistence y no hay una manera general fácil de resolverlo (a menos que el lenguaje y el sistema lo proporcionen). No puede razonar en términos de un hilo, porque el hilo que está considerando hace referencia a otros datos (globales o de montón). Esa pregunta también está relacionada con garbage collection (porque tanto los recolectores de basura como el mecanismo de persistencia tienden a escanear todo el montón dinámico).

0

Probablemente pueda establecer algo como esto con un árbol de expresiones o una cadena de métodos. Configure lambdas o métodos pequeños para las unidades de trabajo "atómicas" más pequeñas que no se pueden interrumpir. Luego, conéctelos con un "supervisor" que ejecutará cada uno de estos trozos en orden, pero se le puede decir que detenga lo que está haciendo entre instrucciones, guarde su posición a lo largo de la cadena, regrese y espere para reanudarse. Si desea el nombre de un patrón, puede llamarlo una variación de Visitante.

+0

Esto es una buena idea y me preguntaba acerca de algo así ... casi como una matriz que está llena de indicadores de función (delegados). Así que solo muevo un puntero a lo largo de la matriz. Mi problema con esta idea es que quiero que mi clase base sea utilizada por otras personas. Creo que hacer algo como esto complicaría demasiado la situación (ya que muchas personas simplemente tendrían tareas que solo tienen un puntero a la función en la matriz). Aunque me gusta esta idea. – i8abug

0

Quiere serializar el estado de su objeto cuando el proceso está en pausa, y luego deserializarlo una vez que se reinicia.

Una implementación muy ingenua sería crear dos métodos estáticos en su clase de tarea Serialize/Deserialize que usan Linq para leer/escribir el estado de su objeto en XML. Cuando una tarea está en pausa, llame a Serialize, que volcará el objeto como xml en el disco, cuando se reinicie, llame a Deserialize, que lee el xml. También existe la clase XmlSerializer que puede ser más robusta.

Independientemente de que este es un problema complejo, con una solución conceptualmente simple.

+0

Parece que básicamente respaldas el método que tengo con la variable IsPaused, ¿verdad? No he pensado demasiado sobre cómo serializaré, pero probablemente sea algo así como lo que dices. Tenía la esperanza de que hubiera una mejor manera de hacerlo, pero quizás de esa manera sea el método estándar para enfrentar esta situación. – i8abug

+0

Con palabras claves, necesitará guardar el estado del objeto si desea pausarlo, y volver a él más tarde. Entonces, sí, serializarás cuando pausar y deserializar a donde llamas 'setupStuff' – Jason

1

Esto se puede lograr muy fácilmente utilizando WF ... tiene todas las tuberías para detener y reanudar tareas explícitamente (y se encarga de la persistencia para usted). Check out this link.

Probablemente no sea adecuado para lo que quiere, pero tal vez valga la pena investigarlo.

Cuestiones relacionadas