2010-09-27 13 views
5

Estoy trabajando en un proyecto en C# .NET utilizando .NET framework versión 3.5.Práctica recomendada para el proceso continuo en C#

Mi proyecto tiene una clase llamada Focuser.cs que representa un dispositivo físico, un enfocador de telescopio, que puede comunicarse con una PC a través de un puerto serie (RS-232). Mi clase (Focuser) tiene propiedades como CurrentPosition, CurrentTemperature, ect, que representan las condiciones actuales del enfocador que pueden cambiar en cualquier momento. Entonces, mi clase Focuser necesita sondear continuamente el dispositivo para estos valores y actualizar sus campos internos. Mi pregunta es, ¿cuál es la mejor manera de realizar esta secuencia continua de sondeo? Ocasionalmente, el usuario deberá cambiar el dispositivo a un modo diferente que requerirá la capacidad de detener el sondeo, realizar alguna acción y luego reanudar el sondeo.

Mi primer intento fue usar un tiempo que marca cada 500ms y luego llama a un trabajador de fondo que luego sondea para una posición y una temperatura. Cuando el temporizador marca si el trabajador de segundo plano es Busy, simplemente regresa e intenta nuevamente 500 ms más tarde. Alguien sugirió que me deshaga del trabajador de fondo y lo haga en el evento tic del temporizador. Así que establecí la propiedad AutoReset del temporizador en falso y luego simplemente reinicié el temporizador cada vez que finaliza una encuesta. Estas dos técnicas parecían comportarse de la misma manera en mi aplicación, así que no estoy seguro de si una es mejor que la otra. También intenté crear un nuevo hilo cada vez que quiero hacer una operación de sondeo usando un nuevo ThreadStart y todo eso. Esto también parecía funcionar bien.

Debo mencionar otra cosa. Esta clase es parte de un servidor de objetos COM que básicamente significa que la biblioteca de clases que se produce se invocará a través de COM. No estoy seguro de si esto tiene alguna influencia en la respuesta, pero pensé que debería arrojarla allí.

La razón por la que estoy preguntando todo esto es que todas mis ejecuciones de prueba y las versiones de depuración funcionan bien, pero cuando hago una compilación de lanzamiento y trato de hacer llamadas a mi clase desde otra aplicación, esa aplicación se congela y Estoy teniendo dificultades para determinar la causa.

Cualquier consejo, sugerencias, comentarios serán apreciados.

Gracias, Jordan

Respuesta

2

Recuerde que el temporizador esconde su propio subproceso de trabajo de fondo, que básicamente tiene capacidad para el intervalo, y luego dispara su caso transcurrido. Sabiendo eso, tiene sentido simplemente poner la votación en transcurrido. Esta sería la mejor práctica de OMI, en lugar de comenzar un hilo de un hilo. También puede iniciar y detener temporizadores, por lo que el código que cambia de modo puede detener() el temporizador, realizar la tarea, luego iniciar() de nuevo, y el temporizador ni siquiera tiene que conocer el telescopio IsBusy.

Sin embargo, lo que yo no perder de vista es si otra instancia del manejador de eventos transcurrido todavía se está ejecutando. Puede bloquear el código del manejador Transcurrido, o puede establecer un indicador, visible desde cualquier hilo, que indique que otro controlador de eventos de Elapsed() todavía está funcionando; Los controladores de eventos transcurridos que ven este conjunto de indicadores pueden salir inmediatamente, evitando problemas de simultaneidad al trabajar con el puerto serie.

0

¿Qué tal comenzar un hilo de fondo con ThreadPool? Luego ingrese un bucle basado en un bool (While (bContinue)) que se repite y hace su trabajo y luego un Thread.Sleep al final del bucle - salir del programa incluiría establecer bContinue en false para que el thread se detenga - quizás engancharlo hasta el evento OnStop en un servicio de windows

bool bRet = ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadFunc)); 
private void ThreadFunc(object objState) 
{ 
    // enter loop 
    bContinue = true; 
    while (bContinue) { 
    // do stuff 
    // sleep 
    Thread.Sleep(m_iWaitTime_ms); 
    } 
} 
+0

algo como: – bigtang

+0

bool BRET = ThreadPool.QueueUserWorkItem (nuevo WaitCallback (ReLoadThreadFunc)); – bigtang

+0

private void ThreadFunc (object objState) {bool bMessageAvailable = false; objeto mensaje = nulo; string strLabel = string.Empty; int iCurChunk = 0; int iTotalChunk = 0; int iCount = 0; Resultado ret; // introduce el bucle bContinue = verdadero; while (bContinue) {// hacer cosas // sleep Thread.Dormir (m_iWaitTime_ms); }} – bigtang

1

Es el proceso de ponerse en contacto con el telescopio y obtener los valores actuales realmente toman el tiempo suficiente como para justificar votación? ¿Has intentado soltar el multihilo y simplemente bloquear mientras obtienes el valor actual?

Para responder a su pregunta, sin embargo, sugeriría no utilizar un trabajador de fondo sino un hilo real que actualice las propiedades continuamente.

Si todas estas propiedades son de solo lectura (¿puede establecer la temperatura del telescopio?) Y no hay dependencias entre ellas (p. Ej., No se requieren transacciones para actualizar varias propiedades a la vez) puede soltar todo el código de bloqueo y deje que su hilo se actualice de cualquier manera, mientras que otros hilos acceden a las propiedades.

Sugiero un subproceso real, dedicado en lugar del grupo de subprocesos solo por falta de conocimiento de lo que podría suceder al mezclar subprocesos de fondo y servidores COM. Además, el estado del departamento podría jugar en esto; con un Thread puedes probar STA pero no puedes hacer eso con un thread de threadpool.

2

lo que parece que usted ha mirado 2 opciones:

  1. temporizador. El temporizador no bloquea mientras espera (usa otro hilo), por lo que el resto del programa puede seguir funcionando y ser receptivo. Cuando se inicia el evento del temporizador, simplemente obtiene/actualiza los valores actuales.

  2. temporizador + BackgroundWorker. El trabajador de fondo también es simplemente un hilo separado. Puede tomar más tiempo iniciar realmente el hilo que simplemente obtener los valores actuales. A menos que tome mucho tiempo obtener los valores actuales y haga que su programa no responda, esta es una complejidad innecesaria.

Si obtener los valores es lo suficientemente rápido, se adhieren a # 1 para mayor simplicidad.

Si conseguir valores es lenta, # 2 funciona, pero innecesariamente ha iniciar un hilo de un hilo. En cambio, hágalo solo con un BackgroundWorker (sin temporizador). Crea el BackgroundWorker una vez y almacena en una variable. No hay necesidad de volver a crearlo cada vez. Asegúrese de establecer WorkerSupportsCancellation en verdadero. Siempre que quiera comenzar a verificar valores, en su cadena de programas principal, haga bgWorker.RunWorkerAsync(). Cuando quieras parar, haz bgWorker.CancelAsync(). Dentro de su método DoWork, tenga un bucle que verifique los valores y haga un Thread.Sleep(500). Como se trata de un hilo separado, no hará que tu programa no responda. En las condiciones del bucle, también verifique si el sondeo se canceló y estalló. Probablemente necesites una forma de volver a poner los valores en el hilo principal. Puede usar ReportProgress() si un número entero es lo suficientemente bueno. De lo contrario, puede crear un objeto para contener el contenido, pero asegúrese de lock (object) { } antes de leerlo y modificarlo. Este es un resumen rápido, pero si sigue esta ruta, le recomiendo que lea: http://www.albahari.com/threading/part3.aspx#_BackgroundWorker

+0

La idea básica de usar solo el BackgroundThread se puede usar también para un Thread normal si necesita más control. –

1

¿Dice que la aplicación se congela en una compilación de lanzamiento? Para eliminar las variables adicionales, sacaría todo el código del temporizador/multihilo de la aplicación (simplemente coméntelo) y lo probaré con un método de bloqueo directo.

es decir, hacer clic en un botón, se llama a una función, esa función golpea el objeto COM para los datos y, a continuación, actualiza la interfaz de usuario. Todo de forma sincronizada y de bloqueo. Esto le dirá con certeza si es el código de multihilo lo que lo está congelando, o si es la interacción COM en sí misma.

+0

¡Me gusta esta idea! Lo probaré – PICyourBrain

Cuestiones relacionadas