Diseño del curso del sistema operativo Basado en C# WinForm: Simulación de tecnología de entrada y salida de spooling spooled.
Se requiere diseñar un proceso de salida de carrete y dos procesos de usuario que soliciten la salida, así como un programa de servicio de salida de spooling. Cuando el proceso del usuario que solicita la salida desea obtener una serie de información, se llama al programa de servicio de salida y el programa de servicio de salida envía la información a la salida bien. Cuando se encuentra un indicador de extremo de salida, indica que se completa la salida del archivo de salida del proceso. Después de eso, se aplica un bloque de solicitud de salida (se utiliza para registrar el nombre del proceso del usuario solicitando la salida, la posición de la información en el pozo de salida, la longitud de la información que se emite, etc.) y esperar a que el proceso de carrete de salida.
Cuando el proceso de salida del botequeo está funcionando, en realidad saldrá a la impresora o monitor en función de la información que se debe emitir por cada proceso registrado en el bloque de solicitudes. Aquí, el proceso de salida SP00LING y el proceso del usuario solicitan la salida se pueden ejecutar simultáneamente.
La programación de procesos utiliza un algoritmo aleatorio, que es consistente con la aleatoriedad de la información de salida del proceso. La probabilidad de programación de los dos procesos de usuario que solicitan la salida es del 45% cada uno, y el proceso de salida del bobino es del 10%, lo que está determinado por la simulación del número aleatorio generado por el generador de números aleatorios.
Hay tres estados básicos del proceso, a saber, ejecutable, espera y fin. El estado ejecutable es el estado en el que el proceso se está ejecutando o esperando la programación; El estado de espera se divide en el estado de espera 1, el estado de espera 2 y el estado de espera 3.
Las condiciones para el cambio de estado son:
① Cuando se ejecuta el proceso, se establece en el estado "final".
② Cuando el programa de servicio envía bien la información de salida a la salida, si encuentra que el bien de salida está lleno, el proceso de llamada se establecerá en "Estado de espera 1".
③ Cuando se emite el proceso de carrete, si la salida está vacía, ingresará "Estado de espera 2".
④ Después de que el proceso de carrete genera un bloque de información, debe liberar inmediatamente el espacio de pozo de salida ocupado por el bloque de información y establecer el proceso esperando la salida al "estado ejecutable".
⑤ Después de que el programa de servicio emite información a la salida bien y forme un bloque de información de solicitud de salida, si el proceso de bobina está en un estado de espera, se establece en el "estado ejecutable".
⑥ Cuando el proceso del usuario solicita el bloque de salida, si no hay un bloque de solicitud disponible, el proceso de llamada ingresa a "Estado de espera 3".
Hay dos procesos de usuario que solicitan salida en el sistema, y los dos procesos se denominan proceso del usuario A y el proceso de usuario B respectivamente. Es posible que el usuario necesite obtener más de un archivo, y los archivos están separados por un indicador de extremo de salida. El indicador de extremo de salida del archivo utilizado en este experimento es #.
El usuario debe ingresar todo el contenido del archivo para obtener durante la fase de inicialización y luego guardarlo en una matriz. Cuando se programa el proceso del usuario, si se cumplen las siguientes tres condiciones: todavía hay un archivo que no se emite, el espacio restante en el pozo de salida puede colocar el archivo hacia abajo, y hay un bloque de solicitud de salida disponible, el archivo se envía al pozo de salida de salida y luego se aplica un bloque de solicitud de salida, y el bloque de solicitudes se agrega a la cola de espera de la solicitud de solicitud, y se espera que el proceso de salida de la salida al programar y la salida.
Cuando es el giro del proceso de salida del carrete para ocupar la CPU, el proceso de salida del carrete primero verifica si hay bloques de salida en el bloque de solicitudes que esperan la cola a la salida, y si no hay NO, ingresa al estado de espera. De lo contrario, se realiza la salida, y luego se libera el espacio de salida de salida y el bloque de salida solicitado correspondiente, y el proceso del usuario que duerme porque no hay bloques de salida disponibles.
El proceso de salida de spooling y el proceso del usuario se pueden ejecutar simultáneamente. Este artículo abstrae el proceso de un proceso de ejecución (el proceso no necesariamente termina después de la ejecución) en una función, cada vez que genera un número aleatorio y ejecuta un cierto proceso de acuerdo con el número aleatorio. Si el proceso se bloquea debido a ciertas situaciones, se generará el próximo número aleatorio y se programará otro proceso. El proceso del usuario y el proceso de salida de spooling están programados a su vez por varias razones, es decir, ejecución concurrente.
Las funciones de todo el sistema se dividen en las siguientes partes: función de inicialización, función de programación, función de proceso del usuario y función de salida de botejado. La función de inicialización se utiliza para implementar la entrada y almacenamiento iniciales de archivos de usuario; La función de despacho implementa la conmutación entre procesos de usuario y procesos de salida de carrete; La función de proceso del usuario implementa una serie de acciones completadas después de programar el proceso; La función de salida de la bobina representa la operación de salida.
El diagrama de flujo general de la operación del sistema se muestra en la Figura 1:
El sistema primero usa la función de inicialización para inicializar la entrada de contenido por parte del usuario, y luego genera un número aleatorio R entre 0 y 1, y juzga si el proceso del usuario debe ejecutarse o el proceso de salida debe ejecutarse de acuerdo con el tamaño de R. Después de ejecutar el proceso del usuario y el proceso de salida, el programa se ejecuta, de lo contrario la programación continuará.
El usuario debe ingresar el contenido que desea "imprimir". La función de inicialización acepta la entrada de contenido por el usuario y la corta de acuerdo con el carácter final del archivo, y coloca el archivo de corte en una matriz, y lo envía bien a la salida cuando el proceso del usuario está programado.
La programación de procesos utiliza un algoritmo aleatorio, y la probabilidad de programación de los dos procesos de usuario que solicitan la salida es del 45%, y el proceso de salida del carrete es del 10%. Este documento usa números aleatorios para lograr este requisito. Al realizar la programación de procesos, se genera aleatoriamente un decimal entre 0 y 1. Si el número es menor o igual a 0.45, el proceso del usuario A se pondrá en funcionamiento; Si el número está entre 0.45 y 0.9, el proceso del usuario B se pondrá en funcionamiento; Si el número es mayor que 0.9, el proceso de salida del bobina se pondrá en funcionamiento.
La función del proceso del usuario primero debe verificar si el proceso actual cumple con tres condiciones: el archivo no se emite, el espacio restante en el pozo de salida puede colocar el archivo hacia abajo y hay un bloque de solicitud de salida disponible. Si se cumplen las tres condiciones, el archivo se enviará bien a la salida y se aplica el bloque de solicitud correspondiente.
El diagrama de flujo de la ejecución de la función del proceso del usuario se muestra en la Figura 2:
Cuando el proceso del usuario se ejecuta, si se encuentra que el archivo ha sido emitido, el proceso se ejecuta en final. De lo contrario, se determina si hay algún espacio restante en la salida bien y no se ingresa ningún estado de espera. Si queda espacio en la salida bien, continúe juzgando si hay un bloque de salida. Si hay uno, envíe bien el archivo a la salida y solicite un bloque de salida, y despierta el proceso de salida potencialmente somnoliento, de lo contrario ingrese el estado de espera 3.
La función de salida de spooling verifica si hay bloques de solicitud de salida, y si existe, salida y liberación de recursos relevantes. De lo contrario, el proceso de salida del carrete esperará.
El diagrama de flujo de la función de salida del boteque se muestra en la Figura 3:
La definición de PCB es la siguiente:
class PCB {
/*
* 进程描述
*/
public int id ; //序号
public int status ; //状态,0表示可执行,123表示三个等待状态,4表示结束
public string [ ] contents = new string [ MaxFileCount ] ; //要输出的内容
public int [ ] flags = new int [ MaxFileCount ] ; //为1表示该文件已经被输出,初始全部为0
public int fileCount ; //用户真实输入的文件个数
}El proceso del usuario incluye la ID del número de serie, el estado del proceso del proceso, el contenido que se emitirá, los indicadores de salida de archivos y el recuento de archivos reales.
Entre ellos, los posibles estados de proceso en el que puede existir el proceso del usuario incluyen: 0 medios estado ejecutable, 1 significa estado de espera 1, 3 medios de espera 3, 4 significa finalizar el proceso.
OutputReqBlock se define de la siguiente manera:
class OutputReqBlock {
/*
* 输出请求块
*/
public int id ; //要求进行输出的进程的id
public int start ; //文件在输出井中的起始位置
public int length ; //文件长度
public int fileIndex ; //要输出文件的序号
public OutputReqBlock ( int id , int start , int length , int fileIndex ) {
this . id = id ;
this . start = start ;
this . length = length ;
this . fileIndex = fileIndex ;
}
}El bloque de salida de la solicitud incluye: el ID de proceso del bloque de solicitud, la posición inicial del archivo en el pozo de salida, la longitud de la longitud del archivo y el número de secuencia del archivo que se emitirá en todos los archivos del usuario.
La definición de Outputwell es la siguiente:
class OutputWell {
/*
* 输出井
*/
public char [ ] buffer = new char [ MaxWellLen ] ; //输出缓冲区
public int begin = 0 ; //当前可用位置
public int restSize = MaxWellLen ; //剩余容量
}Los parámetros del pozo de salida son: búfer de búfer, utilizados para almacenar datos colocados por el usuario; Comienza la ubicación disponible actual, los archivos se almacenan en orden en el pozo de salida, y el comienzo siempre apunta a la posición inicial del búfer actualmente disponible; La capacidad restante reformulada, la capacidad restante en el búfer, inicialmente la longitud del tampón Maxwelllen.
El usuario ingresa a la información para "imprimir" en el cuadro de texto, luego selecciona a qué procesamiento del contenido de salida pertenece (A o B). Finalmente, haga clic en el botón de inicialización para iniciar la función de inicialización. La función de inicialización primero usa un objeto de cadena para almacenar la entrada de contenido por el usuario. Luego, verifique si el contenido ingresado por el usuario termina con un número # y solicite al usuario que vuelva a ingresar si no es legal. Después de que la entrada es legal, el contenido ingresado por el usuario se corta de acuerdo con el número #, y la cadena se corta en múltiples cadenas. Finalmente, un objeto PCB se inicializa utilizando la información generada y se coloca en la cola de espera Waitqueue.
Dado que el usuario puede hacer clic en el botón de inicialización varias veces, es necesario determinar si el proceso actual se ha inicializado antes de cada clic. Si el usuario ya ha completado la inicialización pero hizo clic en el botón de inicialización nuevamente, el contenido original se sobrescribirá.
El pozo de salida se inicializa automáticamente cuando se carga la interfaz del sistema.
¡Se omite el código de función de inicialización!
Para lograr la aleatoriedad, cada vez que desea programar, se genera un número aleatorio entre 0 y 1 utilizando la función aleatoria de C#. Si el número aleatorio es menor o igual a 0.45 significa que el proceso del usuario A se programará a continuación; Si el número aleatorio está entre 0.45 y 0.9 significa que el proceso del usuario B se programará a continuación; Si el número aleatorio es mayor que 0.9 significa que el proceso de salida del carrete se programará a continuación.
La implementación de la función de programador es la siguiente:
private int dispatch ( ) {
/*
* 进程调度
*/
double res = rd . NextDouble ( ) ; //产生一个01之间的小数
if ( res <= 0.45 ) {
return 0 ;
} else if ( res <= 0.9 ) {
return 1 ;
} else {
return 2 ; //012分别表示两个进程和SPOOLing输出进程
}
} Se utiliza para implementar una serie de operaciones realizadas cuando el proceso del usuario se está ejecutando.
Cuando el proceso del usuario está programado, primero verifique si todavía hay archivos que no se han enviado bien a la salida. Si no hay, el proceso de usuario actual se establece en el estado final y la función regresa.
El proceso del usuario aún no ha terminado, lo que significa que todavía hay archivos que no se han enviado bien a la salida. Bucle para encontrar un bloque de archivos que no haya sido emitido (el indicador correspondiente es 1), y luego consulte si el espacio restante en el pozo de salida aún puede colocar este bloque de archivo. Si no, configure el estado del proceso en el estado de espera 1 y la función regrese. Si todavía queda espacio, verifique si todavía hay un bloque de salida de solicitud disponible. Si el proceso no está configurado en Wait State 3, la función regresa. De lo contrario, el bloque de archivo se envía bien a la salida y se modifican los parámetros relevantes del pozo de salida. Luego, se aplica un bloque de salida de solicitud a la cola de salida PrintQueue, y la salida de impresión se imprime cuando se programa el proceso de salida del carrete. Finalmente, si el proceso de salida del carrete está en un estado de espera, el proceso del usuario debe despertarlo.
Diversas situaciones durante la ejecución de la función del proceso del usuario se guardan a través de una lista para la pantalla final de resultados. La lista incluye: el número de secuencia de programación actual, el número de proceso, el estado del proceso, el estado del pozo de salida, el número de bloques de solicitudes disponibles, el número de secuencia de archivos y la longitud del archivo.
¡Se omite el código de función de proceso del usuario!
La función de la función de salida es seleccionar un bloque de salida de solicitud, luego emitir el contenido y finalmente liberar el recurso correspondiente.
Primero verifique si el pozo de salida está vacío. Si el proceso de salida vacío se establece en Wait State 2, la función regresa. De lo contrario, verifique si hay bloques de salida de solicitud en la cola de salida de solicitud que debe ser salida, y ninguna función devuelve. De lo contrario, el bloque de salida de solicitud en el cabezal de la cola se obtiene de la cola de salida de solicitud, y luego se sale el bloque de solicitud, y se libera el espacio de pozo de salida correspondiente y el bloque de solicitud.
Al emitir la función de salida, el contenido de salida debe mostrarse en el área de salida del archivo.
¡Se omite el código de función de salida!
El usuario hace clic en el botón "Programa Ejecutar" y comienza a ejecutar la función principal. El proceso de ejecución se ajusta dinámicamente de acuerdo con la situación actual.
La función principal primero determina si ambos procesos del usuario se han inicializado y solo se pueden ejecutar después de la inicialización, de lo contrario se informará un error.
Después de la inicialización, haga clic en el botón "Programa Ejecutar" nuevamente. Mientras haya un proceso que no esté en el estado final, o no se haya producido un bloque de solicitud, continúe programando. Al programar, debe determinar si el proceso actual ha terminado y producir el estado relevante cuando está terminado.
¡El código de función principal se omite!
La descripción de varios parámetros utilizados en el experimento se muestra en la Tabla 1:
| Nombre de parámetro | Maxwelllen | MaxFilecount | cuaderno |
|---|---|---|---|
| Descripción del parámetro | Longitud del pozo de salida | El número máximo de archivos que un usuario puede emitir | Número de bloques solicitados |
| Valor de parámetro | 15 | 10 | 3 |
La interfaz del sistema se muestra en la Figura 4:
La interfaz del sistema se divide en tres secciones: inicialización, proceso de programación y área de salida de archivos. La sección de inicialización contiene un cuadro de texto, un cuadro de selección y un botón. El usuario ingresa al archivo que se imprimirá en el cuadro de texto y luego lo inicializa. La sección del proceso de programación es principalmente una tabla que muestra el proceso detallado de programación de procesos. La sección de salida del archivo se utiliza para mostrar el proceso de impresión de todos los archivos.
El usuario primero selecciona un proceso, el valor predeterminado inicial es A, y luego coloca el archivo que se emite en el cuadro de texto de la sección de inicialización, y luego hace clic en el botón de inicialización. La inicialización es exitosa, como se muestra en la Figura 5:
Para el proceso B, realice las operaciones anteriores como se muestra en la Figura 6:
Después de completar la inicialización de los dos procesos de usuario, haga clic en el botón Ejecutar del programa y los resultados se muestran en la Figura 7 y la Figura 8:
El siguiente es un breve análisis del contenido de la Figura 7. Como se muestra en la Figura 9:
El proceso de salida se programó por primera vez, porque la salida está vacía en este momento, por lo que el estado del proceso de salida está esperando el estado 2, y el número de bloques de solicitud disponibles es 3. La segunda vez que el proceso A está programado. El estado del proceso A es ejecutable. El número de bloques de solicitudes disponibles es 3. Un archivo envía 0 al pozo de salida. La longitud del archivo 0 ("ABCD") es 4. El proceso de salida está programado por tercera vez. El espacio disponible del pozo de salida es 15-4 = 11, el número de bloques de solicitud disponibles se convierte en 2, y el archivo 0 del proceso A se emite, como se muestra en el área de salida del archivo, y se libera el espacio relevante.