Menú
Está libre
registrarse
el principal  /  Firmware / Aplicaciones multi-roscadas. Aplicaciones multi-roscadas FOR.NET Programas multi-roscadas con ejemplos

Aplicaciones multi-roscadas. Aplicaciones multi-roscadas FOR.NET Programas multi-roscadas con ejemplos

Fin del archivo. Por lo tanto, los registros en el registro, realizados por diferentes procesos, nunca están en relieve. En los sistemas de NUnix más modernos para el registro, se proporciona un servicio especial de syslog (3c).

Beneficios:

  1. Fácil desarrollo. De hecho, lanzamos muchas copias de una aplicación única y trabajan independientemente entre sí. No se puede utilizar ninguna API específicamente multi-roscada y medios de interacción de interprocesado..
  2. Alta fiabilidad. La finalización de emergencia de cualquiera de los procesos no afecta los procesos restantes.
  3. Buena tolerabilidad. La aplicación trabajará en el amor. sistema operativo multitarea
  4. Alta seguridad. Los diferentes procesos de aplicación pueden ejecutarse en nombre diferentes usuarios. Por lo tanto, es posible implementar el principio de privilegios mínimos cuando cada uno de los procesos solo tiene esos derechos que es necesario para el trabajo. Incluso si se detectará un error que permite la ejecución de código remoto en algunos de los procesos, el hacker podrá obtener solo el nivel de acceso con el que se realizó este proceso.

Desventajas:

  1. No todas las tareas aplicadas se pueden proporcionar de esta manera. Por ejemplo, esta arquitectura es adecuada para un servidor de distribución HTML Ranger estático, pero es completamente inadecuado para el servidor de base de datos y muchos servidores de aplicaciones.
  2. La creación y destrucción de los procesos es una operación costosa, por lo que para muchas tareas, tal arquitectura no es óptima.

En los sistemas UNIX, se está realizando toda una gama de medidas para hacer la creación del proceso y el lanzamiento. nuevo programa En el proceso como las operaciones baratas como sea posible. Sin embargo, es necesario comprender que la creación de un hilo dentro del proceso existente siempre será más barato que la creación de un nuevo proceso.

Ejemplos: Apache 1.x (servidor HTTP)

Aplicaciones de multiprocesamiento que interactúan a través de enchufes, tuberías y colas de mensajes Sistema V IPC

El IPC listado (comunicación de interprocesos) pertenece a los llamados agentes de interprensor armónico. Onyindrose para organizar la interacción de los procesos y flujos sin usar la memoria compartida. Los teóricos de programación aman mucho esta arquitectura, porque prácticamente elimina muchas opciones para errores de competencia.

Beneficios:

  1. Facilidad relativa de desarrollo.
  2. Alta fiabilidad. Una finalización de emergencia de uno de los procesos conduce al cierre de la tubería o zócalo, y en el caso de las colas de mensajes, al hecho de que los mensajes dejan de fluir o recuperarse de ella. Los procesos de solicitud restantes pueden detectar fácilmente este error y recuperarse después de que (pero no necesariamente) simplemente reiniciando el proceso rechazado.
  3. Muchas aplicaciones (especialmente en función del uso de los enchufes) se convierten fácilmente al medio distribuido cuando se ejecutan diferentes componentes de la aplicación en diferentes máquinas.
  4. Buena tolerabilidad. La aplicación funcionará en la mayoría de los sistemas operativos multitarea, incluso en sistemas antiguos de UNIX.
  5. Alta seguridad. Los diferentes procesos de aplicación pueden ejecutarse en nombre de diferentes usuarios. Por lo tanto, es posible implementar el principio de privilegios mínimos cuando cada uno de los procesos solo tiene esos derechos que es necesario para el trabajo.

Incluso si se detectará un error que permite la ejecución de código remoto en algunos de los procesos, el hacker podrá obtener solo el nivel de acceso con el que se realizó este proceso.

Desventajas:

  1. No para todas las tareas aplicadas, dicha arquitectura es fácil de desarrollar e implementar.
  2. Todos los tipos listados de medios IPC sugieren transmisión de datos. Si se requiere algún acceso a los datos compartidos, una arquitectura tan incómoda.
  3. La transmisión de datos a través de una cola de tubería, zócalo y mensajes requiere la ejecución de llamadas del sistema y datos de doble copia, primero desde el espacio de direcciones del proceso de origen en el espacio de direcciones del núcleo, luego desde el espacio de direcciones del kernel en la memoria. proceso de destino. Estas son operaciones caras. Al transferir grandes cantidades de datos, esto puede convertirse en un problema grave.
  4. La mayoría de los sistemas tienen limitaciones en el número total de tuberías, sockets y IPC. Por lo tanto, en Solaris de forma predeterminada, no se permiten más de 1024 tubos abiertos, tomas y archivos por proceso (esto se debe a las limitaciones de llamadas del sistema). Restricción arquitectónica de Solaris - 65536 TUBOS, SOCKETS y archivos en el proceso.

    La restricción en el número total de sockets TCP / IP no es más de 65536 en la interfaz de red (debido al formato de los encabezados TCP). Las colas de mensajes del SISTEMA V IPC son colocadas por Vadresan Spitwood, por lo tanto, hay límites difíciles en el número de colas en el sistema y la cantidad y el número de simultáneamente en las colas de los mensajes.

  5. Creación y destrucción del proceso, además de cambiar entre procesos: operaciones costosas. No en todos los casos, tal arquitectura es óptima.

Aplicaciones multiprocesador que interactúan a través de la memoria compartida.

Como memoria compartida, la memoria compartida del Sistema V IPC se puede usar y visualizar los archivos para la memoria. Para sincronizar el acceso, puede usar System V IPC SEMFORES, MUTEXES y POSIX SEMAFORES, al mostrar los archivos a la memoria, capturar las secciones de archivos.

Beneficios:

  1. Acceso arbitrario eficaz a datos compartidos. Dicha arquitectura es adecuada para implementar servidores de bases de datos.
  2. Alta tolerabilidad. Se puede transferir un nuevo sistema operativo que soporta o emulando el sistema V IPC.
  3. Seguridad relativamente alta. Los diferentes procesos están en nombre de diferentes usuarios. Por lo tanto, es posible implementar el principio de privilegios mínimos cuando cada uno de los procesos solo tiene esos derechos que es necesario para el trabajo. Sin embargo, la separación de los niveles de acceso no es tan rígida como en las arquitecturas consideradas anteriormente.

Desventajas:

  1. Complejidad relativa del desarrollo. Errores Al sincronizar el acceso, los llamados errores de competencia, es muy difícil detectar al probar.

    Esto puede llevar a un aumento en el costo total del desarrollo de 3 a 5 veces en comparación con las arquitecturas de multitarea simplificadas o simplificadas.

  2. Baja fiabilidad. Una finalización de emergencia de cualquiera de los procesos de solicitud puede dejar (y, a menudo, deja) la memoria compartida en el estado inconsistente.

    Esto a menudo conduce a una finalización de emergencia de las tareas restantes de la solicitud. Algunas aplicaciones, como Lotus Domino, especialmente matan procesos en todo el tiempo en caso de finalización de emergencias.

  3. Creación y destrucción del proceso y cambio entre ellos: operaciones costosas.

    Por lo tanto, esta arquitectura es óptima para todas las aplicaciones.

  4. Bajo ciertas circunstancias, el uso de la memoria compartida puede llevar a la escalada de privilegios. Si se encuentra un error en uno de los procesos, lo que llevó a una ejecución de código remoto, con una alta probabilidad de un hacker podrá usarlo para la ejecución remota del código en otros procesos de aplicación.

    Es decir, en el peor de los casos, el hacker puede obtener el nivel de acceso correspondiente al más alto de los niveles de aplicación de los procesos de solicitud.

  5. Las aplicaciones que utilizan la memoria compartida deben ejecutarse en una computadora física, en cualquier caso, en las máquinas que tienen una memoria RAM compartida. De hecho, esta restricción puede ser bypass, por ejemplo, utilizando los archivos compartidos que se muestran en la memoria, pero esto conduce a costos generales significativos.

De hecho, esta arquitectura combina las deficiencias de multiprocesamiento y en realidad aplicaciones multinqueadas. Sin embargo, una serie de aplicaciones populares desarrolladas en los años 80 y principios de los 90, antes de que la UNIX haya sido estandarizada API multi-roscada, use esta arquitectura. Estos son muchos servidores de base de datos como Comercial (Oracle, DB2, Lotus Domino), Takisovovo Distribuidos, versiones modernas de Sendmail Incotores otros servidores de correo.

En realidad aplicaciones multi-roscadas

Los flujos o hilos de la aplicación se ejecutan dentro del mismo proceso. Todo el espacio de direcciones del proceso se separa entre hilos. A primera vista, parece que le permite organizar la interacción entre hilos sin ninguna API especial. De hecho, no es así: si varias corrientes funcionan con una estructura de datos dividida o recurso del sistema, y al menos una de las corrientes modifica esta estructura, entonces los datos serán inconsistentes en algunos puntos de tiempo.

Por lo tanto, los flujos deben usar herramientas especiales para organizar la interacción. Los medios más importantes son los primitivos de la exclusión mutua (MACTERES y Cerraduras de lectura-escritura). Usando estas primitivas, el programador puede asegurarse de que no haya una secuencia para que los recursos compartidos estén en el estado inconsistente (esto se denomina surfactante mutuo). SISTEMA V IPC, solo esas estructuras se separan en el segmento de la memoria compartida. Las variables habituales y las estructuras de datos dinámicas se colocan de la manera habitual de sus propios iconos). Errores Tenemos datos relacionados con la competencia apropiadamente relacionados: es muy difícil de detectar al probar.

  • El alto costo de los aplicaciones de desarrollo y depuración, debido al párrafo 1.
  • Baja fiabilidad. La destrucción de las estructuras de datos, por ejemplo, como resultado de los errores de desbordamiento o punto de punta, afecta a todos los hilos del proceso y generalmente conduce a una finalización de emergencia de todo el proceso. Otros errores fatales, como la división en cero en uno de los hilos, generalmente generalmente conducen a la parada de emergencia de todos los hilos del proceso.
  • Baja seguridad. Todos los hilos de la aplicación se ejecutan en un proceso, es decir, en nombre del mismo usuario y con los mismos derechos de acceso. Es imposible implementar el principio mínimo de los privilegios necesarios, el proceso debe ejecutarse en nombre del usuario que pueda ejecutar todas las operaciones necesarias para todos los hilos de la aplicación.
  • Creación de un hilo: una operación aún bastante cara. Para cada hilo, es obligatorio asignado su pila, que de forma predeterminada toma 1 megabyte RAM en arquitecturas de 32 bits y 2 megabytes en arquitecturas de 64 bits y algunos otros recursos. Por lo tanto, esta arquitectura es óptima para todas las aplicaciones.
  • La incapacidad de ejecutar una solicitud en un complejo de computación multimárico. Las recepciones mencionadas en la sección anterior, como mostrar la memoria de los archivos compartidos, no solicitan un programa multi-roscado.
  • En general, se puede decir que las aplicaciones multinfiladas tienen casi las mismas ventajas y desventajas como aplicaciones multiprocesadoras que utilizan la memoria compartida.

    Sin embargo, el costo de ejecutar una aplicación multi-roscada a continuación, y el desarrollo de dicha aplicación de alguna manera es más fácil que las aplicaciones basadas en la memoria informada. Por lo tanto, en los últimos años, las aplicaciones multinfiladas son cada vez más populares.

    Capítulo Número 10.

    Aplicaciones multi-roscadas

    La multitarea en los sistemas operativos modernos se percibe como algo concedido [ Antes de que aparezca Apple OS X en las computadoras Macintosh, no hubo sistemas operativos Modernwing Multitarea. Fue muy difícil diseñar adecuadamente el sistema operativo con una multitarea completa, por lo que el OS X tuvo que tomar el sistema UNIX.]. El usuario cuenta con el hecho de que al comenzar editor de texto y la correza estos programas no entrará en conflicto, y al tomar correo electrónico El editor no dejará de funcionar. Con el lanzamiento simultáneo de varios programas, el sistema operativo cambia rápidamente entre los programas, a su vez, proporcionándoles el procesador (a menos que, por supuesto, varios procesadores estén instalados en la computadora). Como resultado, se crea. espejismooperación simultánea de varios programas, ya que incluso el mejor tipista (y la conexión a Internet más rápida) no será tratada con un procesador moderno.

    La multitudina (multithreading), en algún sentido, se puede considerar como el siguiente nivel de multitarea: en lugar de cambiar entre diferentes programas,sistema operativo Interruptores entre diferentes partes de un programa. Por ejemplo, multi-roscado cliente de correo Le permite tomar nuevos correos electrónicos mientras lee o elabore nuevos mensajes. Hoy en día, muchos usuarios también perciben a MultiThreading.

    En VB, nunca hubo soporte normal para MultiPhreading. Es cierto, en VB5 apareció una de sus variedades. modelo de transmisión conjuntaHilo de apartamento). Como pronto verá, el modelo conjuntos proporciona una parte programadora de las ventajas de los multithreading, pero no permite usar todas las posibilidades para plenamente. Tarde o temprano, es necesario transferir a lo real, y VB .NET se ha convertido en la primera versión de VB con el soporte de un modelo multithreado gratuito.

    Sin embargo, MultiShreading no pertenece a la cantidad de posibilidades que se implementan fácilmente en los idiomas de programación y son masterizados fácilmente por programadores. ¿Por qué?

    Debido a que en aplicaciones múltiples roscadas, pueden ocurrir errores muy complicados, lo que aparece y desaparece de manera impredecible (y tales errores son los más difíciles de depurar).

    Honestamente Advierta: MultiPhreading es una de las áreas de programación más complejas. La más mínima falta de atención conduce a la aparición de errores esquivos, cuya corrección es la cantidad astronómica. Por esta razón, se da mucha razón en este capítulo. maloejemplos: los escribimos intencionalmente para demostrar errores característicos. Este es el enfoque más seguro para aprender la programación multirrocesada: debe poder ver los problemas potenciales cuando a primera vista todo funciona bien y conozca las formas de resolverlas. Si desea utilizar técnicas de programación multi-roscadas, no lo hagas sin él.

    Este capítulo lanzará una base confiable para más trabajo independientePero no podremos describir la programación multi-roscada en todas las complejidades: solo la documentación de impresión para las clases de enhebres del espacio de nombres es de más de 100 páginas. Si desea dominar la programación multi-roscada en un nivel superior, consulte los libros especializados.

    Pero no importa lo peligroso que sea la programación multi-roscada, con una solución profesional de algunas tareas es indispensable. Si sus programas no usan MultiPhreading, donde sea apropiado, los usuarios desaparecerán en gran medida y preferirán otro producto. Por ejemplo, solo en la cuarta versión del popular programa postal de Eudora ha emergido las posibilidades multinqueadas, sin las cuales es imposible imaginar que cualquier programa moderno funcione con correo electrónico. Para cuando Eudora hubo apoyo para MultiPhreading, muchos usuarios (incluido uno de los autores de este libro) cambiado a otros productos.

    Finalmente, los programas de un solo hilo v.net simplemente no suceden. Todoel software .NET se realizan multithread, ya que el recolector de basura se ejecuta como un proceso de fondo de baja prioridad. Como se muestra a continuación, con una programación gráfica seria de V.NET, la interacción correcta de los flujos de software ayuda a prevenir el bloqueo de la interfaz gráfica al ejecutar el programa para operaciones de larga duración.

    Conocido con multithreading

    Cada programa funciona en un determinado contextodescribiendo la distribución de código y datos en la memoria. Cuando se guarda el contexto, se guarda el estado de la corriente de software, lo que le permite restaurarlo en el futuro y continuar la ejecución del programa.

    Contexto de conservación asociado con ciertos costos de tiempo y memoria. El sistema operativo recuerda el estado del flujo de software y transmite el control a otro flujo. Cuando el programa quiere continuar la ejecución del flujo suspendido, el contexto guardado debe restaurarse, lo que es aún más tiempo. En consecuencia, los multiplicados deben usarse solo en los casos en que los beneficios compensen todos los costos. Algunos ejemplos típicos se enumeran a continuación.

    • La funcionalidad del programa se divide claramente y naturalmente en varias operaciones heterogéneas, como en el ejemplo con la recepción de correo electrónico y la preparación de nuevos mensajes.
    • El programa realiza cálculos largos y complejos, y no desea que la interfaz gráfica se bloquee en el momento de los cálculos.
    • El programa opera en una computadora multiprocesador con un sistema operativo que admite el uso de múltiples procesadores (siempre que el número de transmisiones activas no exceda el número de procesadores, los costos de ejecución paralelos casi sin costos asociados con los flujos de conmutación).

    Antes de pasar a la mecánica de trabajo de los programas multinhoscados, es necesario señalar una circunstancia, lo que a menudo causa malentendidos de principiantes en el campo de la programación multi-roscada.

    El hilo del programa se realiza y no es un objeto.

    Es difícil decir que debe entenderse en virtud de la expresión "Objeto se realiza", pero uno de los autores a menudo lleva a los seminarios sobre la programación multinqueada y se pregunta a esta pregunta con más frecuencia que otras. Tal vez alguien cree que la operación de la corriente de software comienza con la llamada del método de nueva clase, después de lo cual el flujo procesa todos los mensajes transmitidos al objeto apropiado. Tales ideas absolutamenteinnecesario. Un objeto puede contener varios hilos que realizan métodos diferentes (y, a veces, incluso los mismos), y los mensajes de objeto son transmitidos y aceptados por varios hilos diferentes (por cierto, esta es una de las razones que hacen que la programación de múltiples roscadas: para depurar El programa, necesitas saber en qué flujo en este momento Realiza uno u otro procedimiento!).

    Dado que las transmisiones de software se crean sobre la base de los métodos de objeto, el objeto en sí se crea generalmente antes de la corriente. Después de crear con éxito un objeto, el programa crea un flujo pasando la dirección del método del objeto y solo después de esorecupera el inicio de la corriente. El procedimiento para el cual se creó un flujo, como todos los procedimientos, puede crear nuevos objetos, realizar operaciones con los objetos existentes y causar otros procedimientos y funciones que están en su alcance.

    En los flujos de software, también se pueden realizar clases generales. En este caso, también recuerde otra circunstancia importante: el flujo se completa con la salida del procedimiento para el cual se creó. Antes de salir del procedimiento, la finalización normal de la corriente de software no es posible.

    Los hilos pueden terminar no solo naturalmente, sino también de emergencia. Por lo general, no se recomienda. Para obtener más información, consulte la sección "Finalización e interrupción".

    Fondos básicos .NET relacionados con el uso de flujos de software se concentran en el enhebrado del espacio de nombres. En consecuencia, la mayoría de los programas multi-roscados deben comenzar con la siguiente línea:

    Sistema de importaciones.

    Importar el espacio de nombres simplifica la entrada del programa y le permite usar la tecnología IntelliSense.

    Los enlaces directos de los flujos con procedimientos sugieren que en esta imagen se ocupa un lugar importante. delegados(Ver Capítulo 6). En particular, el espacio de nombres de subprocesos incluye el delegado de ThreadStart, comúnmente utilizado al ejecutar Software Streams. La sintaxis de usar este delegado se ve así:

    Delegado público Sub ThreadStart ()

    El código llamado utilizando el delegado de ThreadStart no debe tener parámetros y el valor de retorno, por lo que las transmisiones no se pueden crear para funciones (que devuelven el valor) y para los procedimientos con parámetros. Para transmitir información desde la secuencia, también debe buscar medios alternativos, ya que los métodos realizados no devuelven los valores y no pueden usar el enlace por referencia. Por ejemplo, si el procedimiento de SHOPTETHOD está en la clase WillusethRead, entonces ROPTETETHOD puede transmitir información cambiando las propiedades de las instancias de la clase WillusethRead.

    Aplicaciones de dominios

    Los flujos de software .NET operan en los llamados dominios de la aplicación definidos en la documentación como el "entorno aislado en el que se ejecuta la aplicación". El dominio de la solicitud se puede considerar como una variante liviana de los procesos WIN32; Un proceso WIN32 puede contener múltiples dominios de aplicación. La principal diferencia entre los dominios de las aplicaciones y los procesos es que el proceso WIN32 tiene un espacio de direcciones independiente (la documentación del dominio de la aplicación también se compara con procesos lógicos que trabajan dentro del proceso físico). V.net Toda la administración de la memoria es realizada por el entorno ejecutivo, por lo que varios dominios de solicitud pueden operar en un proceso WIN32. Una de las ventajas de este esquema es mejorar las capacidades de escalado de aplicaciones (escalado). Los medios para trabajar con dominios de aplicaciones están en la clase AppDomain. Recomendamos explorar la documentación de esta clase. Con él, puede obtener información sobre el entorno en el que funciona su programa. En particular, la clase AppDomain se usa al realizar la reflexión para las clases del sistema .NET. El siguiente programa muestra una lista de ensamblajes descargados.

    Sistema de importaciones.Reftle

    Módulo Módulo

    Sub principal ()

    Dim thedomain como appdomain

    thedomain \u003d appdomain.currentdomain.

    Ensamblajes tenues () como

    Asambleas \u003d thedomain.getassemblies.

    Dim Aassemblyxas.

    Para cada anejo en ensamblajes.

    Console.writelinetanassembly.full nombre) Siguiente

    Console.readline ()

    Sub. Sub.

    Módulo final.

    Creando arroyos

    Vamos a empezar con un ejemplo elemental. Supongamos que desea iniciar un procedimiento en un flujo por separado, que en un bucle infinito reduce el valor del contador. El procedimiento se determina como parte de la clase:

    Clase pública willusethreads.

    Public Sub SubtractFromCounter ()

    Tendencia tenue como entero

    Hazlo mientras cuenta verdadera - \u003d 1

    Consola.writellne ("estoy en otro hilo y contador \u003d"

    & Contar)

    Círculo.

    Sub. Sub.

    Clase final

    Dado que la condición de ciclo de DO siempre permanece cierta, puede pensar que nada evitará la implementación del procedimiento de SubtractFromCounter. Sin embargo, en una aplicación multi-roscada, este no es siempre el caso.

    El siguiente fragmento proporciona el procedimiento SUB principal que inicia la secuencia y el comando Imports:

    Opción estricta en el sistema de importaciones. Módulo de módulo de prensa.

    Sub principal ()

    1 Dim Mytest como nuevo willusethreads ()

    2 DIM BTHTHETSTARTT AS NEW RHEADSTART (Dirección de _

    mytest.subtractfromcounter)

    3 DIM BRTHEAD como nuevo hilo (BTHTRADSTART)

    4 "bthread.start ()

    Dim I como entero

    5 Hacer mientras sea cierto

    Console.writeline ("en hilo y conteo principal es" & i) i + \u003d 1

    Círculo.

    Sub. Sub.

    Módulo final.

    Analicemos secuencialmente los momentos más principales. En primer lugar, el procedimiento Sub Man n siempre funciona en flujo principal(Hilo principal). En el programa-max.net siempre opere al menos dos flujos: el principal y el hilo de la recolección de basura. La línea 1 crea una nueva instancia de clase de prueba. En la Línea 2, creamos un delegado de ThreadStart y transmitimos la dirección del procedimiento SubtractFromCounter de la instancia de la clase de prueba creada en la línea 1 (este procedimiento se llama sin parámetros). Biendando un espacio de nombres de roscado importando un nombre largo. No puede especificar un nombre largo. El objeto de la nueva corriente se crea en la línea 3. Preste atención a la transmisión del delegado de ThreadStart al llamar al constructor de clase de hilo. Algunos programadores prefieren combinar estas dos líneas en una cadena lógica:

    Dim BRTHEAD como nuevo hilo (Nuevo ThreadStartTAdRessof _

    mytest.subtractfromcounter))

    Finalmente, la línea 4 "comienza" el flujo, para el cual se llama la instancia de instancia de inicio de la clase de subproceso creada para el delegado de ThreadStart. Llamando a este método, especificamos el sistema operativo que el procedimiento reste debe funcionar en un flujo por separado.

    La palabra "se inicia" en el párrafo anterior está en las cotizaciones, ya que en este caso se observa una de las muchas raras de la programación multi-roscada: ¡la llamada de inicio no conduce al inicio de la secuencia real! Solo informa que el sistema operativo debe programar la ejecución del flujo especificado, pero el lanzamiento inmediato está fuera del control del programa. No puede comenzar a realizar hilos a su discreción, ya que el sistema operativo siempre se administra realizando flujos. En una de las siguientes secciones, aprenderá cómo con la ayuda de la prioridad para forzar al sistema operativo para ejecutar rápidamente su flujo.

    En la Fig. 10.1 muestra un ejemplo de lo que puede ocurrir después de iniciar el programa y su interrupción posterior con la tecla CTRL + Break. En nuestro caso, ¡el nuevo hilo comenzó solo después de que el mostrador en la corriente principal aumentó a 341!

    Higo. 10.1. Simplemente software multi-roscado

    Si el programa funcionará durante un tiempo mayor, el resultado se verá como lo que se muestra en la FIG. 10.2. Vemos que ustedel ajuste de la corriente de funcionamiento se suspende y el control se transmite nuevamente a la corriente principal. En este caso, hay una manifestación. desplazando a muchas gopotosidad por la cuantización del tiempo.El significado de este término aterrador se explica a continuación.

    Higo. 10.2. Cambiar entre hilos en un simple programa multi-roscado

    Al interrumpir los flujos y la transmisión de control a otros hilos, el sistema operativo utiliza el principio de desplazamiento multitripado por la cuantización del tiempo. La cuantificación del tiempo también resuelve uno de los problemas comunes que surgieron antes en los programas de múltiples roscados: un hilo ocupa todo el tiempo del procesador y no es inferior al control de otros hilos (como regla general, ocurre en ciclos intensivos como los anteriores). Para evitar la captura de monopolio del procesador, sus flujos tienen que transmitir el control de otro hilo de vez en cuando. Si el programa será "inconscriptivo", hay otra solución menos deseable: el sistema operativo siempre desplaza el flujo de trabajo independientemente de su nivel prioritario para que el acceso al procesador se proporcione a cada flujo en el sistema.

    Debido a que en los esquemas de cuantificación de todas las versiones de Windows, en las que se asigna el número de tiempo mínimo a cada transmisión, los problemas de programación .NET con la captura de monopolio del procesador no son tan graves. Por otro lado, si un entorno .NET será adaptado para otros sistemas, la situación puede cambiar.

    Si habilita la siguiente línea en nuestro programa antes de que comience a iniciar sesión, incluso los hilos con una prioridad mínima recibirán alguna participación de tiempo de procesador:

    bthread.priority \u003d threadpriority.highest

    Higo. 10.3. El arroyo con la máxima prioridad generalmente comienza a funcionar más rápido.

    Higo. 10.4. Se proporciona el procesador y reduce los flujos de prioridad.

    El equipo asigna un nuevo flujo a la máxima prioridad y reduce la prioridad de la corriente principal. De la fig. 10.3 Se puede ver que la nueva corriente comienza a funcionar más rápido que antes, pero, como la FIG. 10.4, la corriente principal también recibe el control.verdadero (aunque, muy brevemente y solo después de un trabajo de flujo de larga duración con la resta). Cuando inicie el programa en sus computadoras, los resultados se obtendrán similares a los que se muestran en la FIG. 10.3 y 10.4, pero debido a las diferencias entre nuestros sistemas, no habrá una coincidencia precisa.

    El tipo de THETPRLLORITY TIPO LISTED DE TIPO incluye valores para cinco niveles de prioridad:

    ThreadProriority.Hight.

    ThreadPriority.abovenormal.

    ThreadPrlority.Normal

    ThreadPriority.Bebownormal.

    ThreadPriority.Lowest

    Método de unión

    A veces, se requiere el hilo del programa para suspender hasta que se complete otra corriente. Supongamos que desea pausar el flujo 1 hasta que el flujo 2 complete sus cálculos. Para esto de la corriente 1.el método de unión se llama para Stream 2. En otras palabras, el equipo

    hilo2.join ()

    suspende la corriente actual y espera completar el flujo 2. El flujo 1 entra en estado bloqueado.

    Si conecta la secuencia 1 para fluir 2 por el método de unión, el sistema operativo iniciará automáticamente la flujo 1 después de la finalización de la secuencia 2. Tenga en cuenta que el proceso de inicio es no determinístico:es imposible decirlo seguro, después de lo cual, después de la finalización del flujo 2, obtendrá flujo 1. Hay otra versión de unirse, lo que devuelve un valor lógico:

    thread2.Join (entero)

    Este método está esperando la finalización del flujo 2, o desbloquea flujo 1 después de la expiración del intervalo de tiempo especificado, como resultado de lo cual el programador del sistema operativo resaltará nuevamente el tiempo del procesador. El método devuelve VERDADERO si el flujo 2 se completa antes de que expire el intervalo de tiempo de espera especificado, y falso es de otra manera.

    No olvide la regla básica: independientemente de si la corriente 2 terminó o el tiempo de espera ha terminado, no puede controlar el momento de la activación del flujo 1.

    Nombres de flujo, etththread y Thinkstate

    La propiedad Thread.CurrentThread devuelve una referencia al objeto de flujo realizado en este momento.

    Aunque para la depuración de aplicaciones múltiples roscadas en VB .NET, hay una ventana de transmisión notable, que se describe aún más, a menudo vimos al equipo.

    Msgbox (hilo.currentthread.name)

    A menudo se encontró que el código se realiza en todo en la transmisión en la que se suponía que se debía realizar.

    Recuerde que el término "planificación de software no determinista" significa una cosa muy simple: prácticamente no hay fondos en la eliminación del programador para afectar el planificador de trabajo. Por esta razón, los programas a menudo utilizan la propiedad de ThreadState que devuelve información sobre el estado actual de la transmisión.

    Ventana corriente

    Windows Window Visual Studio .NET proporciona asistencia invaluable en la depuración de programas multinqueados. Está activado por el comando DEBUG\u003e Submenú de Windows en modo de interrupción. Supongamos que asignó el nombre del flujo BRTHEAD mediante el siguiente comando:

    bthread.name \u003d "restando el hilo"

    La vista aproximada de las ventanas de transmisión después de interrumpir el programa por la combinación CTRL + ROTT KEY (o de otra manera) se muestra en la FIG. 10.5.

    Higo. 10.5. Ventana corriente

    Una flecha en la primera columna está marcada con una corriente activa devuelta por la propiedad Thread.CurrentThread. La columna de ID contiene identificadores de flujo numéricos. La siguiente columna enumera los nombres de los hilos (si fueron asignados). La columna de ubicación especifica el procedimiento realizado (por ejemplo, el procedimiento de escritura de la consola en la FIG. 10.5). Las columnas restantes contienen información prioritaria y flujos suspendidos (consulte la siguiente sección).

    La ventana de la corriente (y no el sistema operativo) le permite administrar los flujos de su programa utilizando los menús de contexto. Por ejemplo, puede detener la secuencia de corriente, para la cual debe hacer clic en la fila correspondiente con el botón derecho del mouse y seleccionar el comando congelar (más adelante se puede reanudar el funcionamiento de la corriente de parada). Detener los flujos con frecuencia se utilizan cuando se deprima para que la transmisión de trabajo incorrectamente no interfiera con la aplicación de la aplicación. Además, la ventana de transmisión le permite activar otro flujo (no detenido); Para hacer esto, haga clic con el botón derecho en la línea deseada y seleccione menú de contexto El conmutador a comando de rosca (o simplemente haga un doble clic en la fila de transmisión). A medida que se mostrará el Dalee, es muy conveniente al diagnosticar posibles cerraduras mutuas (puntos muertos).

    Flujo de ahorro

    Los corrientes no utilizados temporalmente se pueden traducir al estado pasivo por el método de Sleer. La corriente pasiva también se considera bloqueada. Por supuesto, con la transferencia de flujo hacia el estado pasivo a la parte de los flujos restantes obtendrá más recursos de procesadores. La sintaxis del Método Sleer estándar se ve así: Hilo.Sleep (interval_v_millies)

    Como resultado de llamar al sueño, la corriente activa entra en un estado pasivo al menos a una cantidad dada de milisegundos (sin embargo, la activación inmediatamente después de la expiración del intervalo especificado no está garantizado). Nota: Al llamar al método, la referencia a una corriente específica no se transmite: el método de suspensión se llama solo para la transmisión activa.

    Otra versión del sueño hace que el flujo actual cierta desde la parte restante del tiempo de procesador asignado:

    Hilo.SLEEP (0)

    La siguiente opción traduce la corriente actual al estado pasivo a tiempo ilimitado (la activación se produce solo cuando las llamadas inerpt):

    Hilo.SEER (tiempo de espera.infinito)

    Dado que los corrientes pasivos (incluso con un tiempo de espera ilimitado) pueden interrumpirse por el método de interrupción, lo que conduce al inicio de la línea de rotura, la llamada de Sleer siempre se encuentra en el bloque de prueba, como en el siguiente fragmento:

    Intentar.

    Hilo.SLEEP (200)

    "El estado pasivo de la corriente fue interrumpido.

    Catch e como excepción

    "Otras excepciones

    Intento final.

    Cada programa .NET funciona en una transmisión de software, por lo que el método de suspensión también se usa para suspender los programas (si el programa de nombres de ThreadIPG no es importado, debe usar el enhebrado de nombre completo. Dormir).

    Finalización o interrupción de los flujos de software.

    El flujo se completa automáticamente cuando se sale del método especificado al crear el delegado de ThreadStart, pero a veces se requiere que complete el método (en consecuencia, el flujo) cuando ocurren ciertos factores. En tales casos, los flujos suelen ser revisados. variable condicionaldependiendo del estado de quese realiza la decisión de la producción de emergencia del flujo. Como regla general, para esto, el procedimiento incluye un ciclo HACE MIENTRAS:

    Sub ThreedMethod ()

    "El programa necesita proporcionar una encuesta

    "Variable condicional.

    "Por ejemplo, una variable condicional puede ser emitida como una propiedad.

    HACER MIENTRAS CONDICIONES VARIABLE \u003d FALSO Y MOREWORKTOTO

    "Código principal

    Subvención de bucle sub.

    La encuesta de la variable condicional lleva algún tiempo. Se debe usar una encuesta permanente en la condición del ciclo solo si espera que se complete la transmisión prematura.

    Si la verificación de la variable condicional debe ocurrir en un lugar estrictamente definido, use el comando IF-SEN en combinación con SALIR SUB dentro del ciclo infinito.

    El acceso a la variable condicional debe sincronizarse de modo que el impacto de otros hilos no impida su uso normal. Este tema importante dedicado a la "solución del problema: sincronización".

    Desafortunadamente, el código de flujos pasivos (o bloqueados de lo contrario) no se realiza, por lo que la variante con una encuesta de la variable condicional no es adecuada para ellos. En este caso, se debe llamar al método de interrupción para una variable de objeto que contiene una referencia al flujo deseado.

    El método de interrupción solo se puede llamar para flujos para esperar, dormir o unirse. Si llama a interrupción de un flujo ubicado en uno de los estados enumerados, después de un tiempo, el hilo comenzará a funcionar nuevamente, y el entorno ejecutivo inicia la excepción del estropajo. Esto está sucediendo, incluso si el flujo se ha traducido a un estado pasivo por un período indefinido de llamando al hilo.Sleepdimeout. Infinito). Decimos "después de algún tiempo", la planificación de los flujos tiene una naturaleza no determinista. La excepción del ThreadlntruprruptiExcepis se intercepta por la sección de captura que contiene el código de salida desde el estado de espera. Sin embargo, la sección de captura no está obligada a completar la transmisión de llamadas de interrupción: el flujo procesa la excepción a su discreción.

    El método de interrupción V.NET se puede llamar incluso para flujos desbloqueados. En este caso, la corriente se interrumpe bajo el bloqueo más cercano.

    Suspendiendo y destrucción de flujos.

    El espacio de nombres en roscado contiene otros métodos que interrumpen la función de flujo normal:

    • Suspender;
    • ABORTAR.

    Es difícil decir por qué V.NET ha incluido el apoyo a estos métodos: al llamar a un suspensión y abortar, lo más probable es que el programa comience a trabajar inestable. Ninguno de los métodos le permite deinitializar normalmente la corriente. Además, al llamar a un suspensión o abortar no se puede predecir, en qué estado el flujo dejará los objetos después de la pausa o el bloqueo.

    Como resultado, la llamada de abortar se inicia a la excepción de Threadabortexception. Para que entienda por qué esta extraña excepción no debe ser procesada en los programas, traemos un extracto de la documentación .NET SDK:

    "... Cuando destruyes el flujo llamando a un abort, el entorno ejecutivo inicia la excepción de Threadabortexception. Este es un tipo especial de excepción que no se puede interceptar el programa. Al iniciar esta excepción antes de destruir el flujo, el entorno ejecutivo realiza todos los bloques finalmente. Dado que se pueden realizar cualquier acción en Finalmente, los bloques, llame a la llamada para asegurarse de que la corriente esté destruida ".

    Moral: el abortar y el uso de suspensión no se recomienda (y si sin suspender, aún no lo hacen, reanude el flujo suspendido por el método de reanudación). Es posible completar de forma segura el flujo solo al sondear la variable condicional sincronizada o llamar al método de interrupción, que se mencionó anteriormente.

    Corrientes de fondo (demonios)

    Algunos flujos que se ejecutan en segundo plano dejarán de funcionar automáticamente en el momento en que se detienen otros componentes del programa. En particular, el recolector de basura funciona en una de las corrientes de fondo. Por lo general, las corrientes de fondo se crean para recibir datos, pero esto se realiza solo si el código que puede procesar los datos obtenidos funciona en otros hilos. Sintaxis: Nombre de flujo.Sebackground \u003d verdadero

    Si solo los flujos de fondo permanecen en la aplicación, la aplicación finaliza automáticamente.

    Ejemplo más serio: extraer datos del código HTML

    Recomendamos utilizar flujos solo cuando la funcionalidad del programa está claramente dividida en varias operaciones. Buen ejemplo Es un programa de extracción de datos del código HTML del Capítulo 9. Nuestra clase realiza dos operaciones: datos de muestreo de Amazon y su procesamiento. Tenemos un ejemplo ideal de una situación en la que la programación multi-roscada es realmente apropiada. Creamos clases para varios libros diferentes y luego analizamos los datos en diferentes flujos. Crear un nuevo flujo para cada libro Mejora la eficiencia del programa, ya que durante la recepción de estos por un hilo (que puede requerir expectativas en el servidor de Amazon), se ocupará otra corriente por el procesamiento de los datos ya recibidos.

    La versión multi-roscada de este programa funciona de manera más eficiente en una versión de un solo roscado en una computadora con múltiples procesadores o si se reciben datos adicionales de manera efectiva combinada con su análisis.

    Como se mencionó anteriormente, solo los procedimientos que no tienen parámetros se pueden iniciar en los flujos, por lo que tendrá que hacer pequeños cambios en el programa. A continuación se muestra el procedimiento principal reescrito con la excepción de los parámetros:

    Sub FindRank público ()

    m_rank \u003d scrapeamazon ()

    Console.writeline ("El rango de" & m_name & "is" & getRank)

    Sub. Sub.

    Dado que no podremos usar el campo combinado para almacenar y enviar información de muestreo (escribiendo programas multi-roscados con interfaz gráfica Se considera en la última sección de este capítulo), el programa conserva los datos de cuatro libros en la matriz, cuya definición comienza como:

    Dim TheBook (3.1) como String TheBook (0.0) \u003d "1893115992"

    theBook (0.l) \u003d "Programación VB .NET" ", etc.

    Se crean cuatro arroyos en el mismo ciclo en el que se crean los objetos de AmazonRanker:

    Para i \u003d 0 entonces 3

    Intentar.

    theranker \u003d New AmazonRanker (TheBook (I.0). TheBookd.1))

    athReadStart \u003d Nuevo Threadstar (dirección de THETANKER.FINDRAN ()

    athread \u003d nuevo hilo (athReadstart)

    athread.name \u003d TheBook (i.l)

    athread.start () Catch e como excepción

    Console.writeline (e.message)

    Intento final.

    próximo

    A continuación se muestra el texto completo del programa:

    Opción estricta en Imports System.io Imports System.Net

    Sistema de importaciones.

    Módulo Módulo

    Sub principal ()

    Dim theBook (3.1) como cadena

    theBook (0.0) \u003d "1893115992"

    theBook (0.l) \u003d "Programación VB .NET"

    theBook (L.0) \u003d "1893115291"

    libro (L.L) \u003d "Programación de bases de datos VB .NET"

    theBook (2.0) \u003d "1893115623"

    theBook (2.1) \u003d "programmer" s introducción a C # ".

    theBook (3.0) \u003d "1893115593"

    theBook (3.1) \u003d "Glándula de la plataforma .NET"

    Dim I como entero

    Dim Tilanker como \u003d AmazonRanker

    Dim AthReadStart como roscado.

    Dim Athread como roscado.

    Para i \u003d 0 a 3

    Intentar.

    theranker \u003d nuevo AmazonRankerttheBook (I.0). El libro (I.1))

    athReadstart \u003d Nuevo ThreadStart (AddRank Dirección de FindRank)

    athread \u003d nuevo hilo (athReadstart)

    athread.name \u003d TheBook (i.l)

    athread.start ()

    Catch e como excepción

    Console.writellte.message)

    Terminar intente a continuación.

    Console.readline ()

    Sub. Sub.

    Módulo final.

    Clase pública amazonranker

    Privado m_url como cadena

    Private M_Rank como entero

    Privado m_name como cadena

    Sub nuevo público (Byval ISBN como cadena. Byval luego como cadena)

    m_url \u003d "http://www.amazon.com/exec/obidos/asin/" & isbn

    m_NAME \u003d Sub final de Themame

    Public Sub FindRank () M_Rank \u003d ScrapAcon ()

    Console.writeline ("el rango de" & m_name & "es"

    & GetRank) Fin Sub

    Propiedad pública readonly getRank () como cadena consigue

    Si m_rank.<> 0 entonces.

    Devuelve CSTR (M_RANK)

    " Problemas

    Terminara si

    Fin Get.

    Propiedad final.

    Propiedad lódica pública getName () como cadena consigue

    Devuelve M_NAME.

    Fin Get.

    Propiedad final.

    Función privada scrapeamazon () como intento entero

    Dim Thurl como nuevo URI (M_URL)

    Tim Aness Posto como WebRequest

    aness POST \u003d webRequest.Create (Theurl)

    Dim ThatSponse como WEBRESPONSE

    theresponse \u003d tyspest.getResponse

    Dim Aladers como nuevo liderazedor (Theresponse.getResponsestream ())

    Dim thedata como cadena

    thedata \u003d ateader.readtoend.

    Analizar de retorno (TEMADA)

    Catch e como excepción

    Console.writeline (e.message)

    Console.writeline (e.stacktrace)

    Consola. Readline ()

    Función final de intento.

    Analizar la función privada (Byval thedata como cadena) como entero

    Ubicación tenue como.integer Ubicación \u003d thedata.indexof (" Amazon.com.

    Rango de ventas:") _

    + "Rango de ventas de Amazon.com:".Largo.

    Temporada tenue como cadena

    Hacer hasta thedata.substring (location.l) \u003d "<" temp = temp

    & thedata.substring (location.l) Ubicación + \u003d 1 bucle

    Devolver CLNT (TEMP)

    Función final.

    Clase final

    Las operaciones multi-roscadas a menudo son utilizadas por V.Net y los nombres de entrada: usted-agua, por lo tanto, en la biblioteca .NET Framework, se proporcionan métodos asíncronos especiales para ellos. INFORMACIÓN ADICIONAL sobre el uso de métodos asíncronos al escribir programas multinfilados en la descripción de los métodos SIGNIFICADOS DE SIGNIFICACIÓN Y ENDGETRESPONSE HTTPWEBREQUEST

    PELIGRO DE HOGAR (DATOS GENERALES)

    Hasta ahora, se considera el único caso seguro de transmisión. nuestros arroyos no han cambiado los datos comunes.Si permite el cambio en los datos generales, los errores potenciales comienzan a hacerse realidad en la progresión geométrica y deshacerse de ellos, el programa se vuelve mucho más difícil. Por otro lado, si prohíbe la modificación de los datos generales por diferentes hilos, la programación multithreadizada .NET no se diferirá de las posibilidades limitadas de VB6.

    Se ofrece un pequeño programa a su atención, lo que demuestra problemas emergentes sin profundizar en detalles innecesarios. La casa se simula en este programa, en cada habitación del cual se instala el termostato. Si la temperatura es de 5 o más grados Fahrenheit (aproximadamente 2.77 grados Celsius) menos establecidos, pedimos que el sistema de calefacción aumente la temperatura de 5 grados; De lo contrario, la temperatura aumenta solo en 1 grado. Si la temperatura actual es más o igual al especificado, no se realiza el cambio. El ajuste de temperatura en cada habitación se realiza mediante un flujo separado con un retraso de 200 mΩcond. El trabajo principal se realiza mediante el siguiente fragmento:

    Si mhouse.houseetemp< mHouse.MAX_TEMP = 5 Then Try

    Hilo.SLEEP (200)

    Catch Late como ThreadlntruptException

    "La espera pasiva fue interrumpida

    Catch e como excepción

    "Otras excepciones terminan intentando

    mhouse.houseetemp + - 5 ", etc.

    A continuación se muestra el código fuente completo del programa. El resultado se muestra en la figura. 10.6: ¡La temperatura en la casa alcanzó los 105 grados Fahrenheit (40.5 grados Celsius)!

    1 opción estricta en

    2 Sistema de importaciones.

    Módulo de 3 módulos

    4 SUB PRINCIPAL ()

    5 Dim MyHouse como nueva casa (L0)

    6 consola. Readline ()

    7 subvención final

    8 módulo final.

    9 Casa de clase pública

    10 Public Const MAX_TEMP como entero \u003d 75

    11 MCURTEMP privado como entero \u003d 55

    12 Mroms privados () como habitación

    13 subvenciones públicas (Byval Numofroms como entero)

    14 Redim Mromss (numofrooms \u003d 1)

    15 DIM i como entero

    16 Dim AthReadStart como roscado.

    17 Dim Athread como hilo

    18 para i \u003d 0 a numofroms -1

    19 intento.

    20 MROMS (I) \u003d NEWOOM (ME, MCURTEMP, CSTR (I) y THRROHER)

    21 AthReadStart - Nuevo ThreadStart (Dirección de _

    mroms (i) .CheckTemPinomage)

    22 Athread \u003d nuevo hilo (AthReadStart)

    23 Athread.start ()

    24 catch e como excepción

    25 console.writeline (e.stacktrace)

    26 fin de intento.

    27 Siguiente

    28 Sub. Sub.

    29 Propiedad Pública HOUTETEMP () TAN INTEGER

    treinta . Obtener.

    31 Regreso MCURTEMP

    32 Get Get.

    33 Set (valor byval como entero)

    34 MCURTEMP \u003d Set de fin de valor 35

    36 propiedad final.

    37 clase final

    38 sala de clase pública

    39 MCURTEMP privado como entero

    40 MNAME privado como cadena

    41 Casa privada como casa

    42 PUBLIC Sub New (Byval Threuse como casa

    TEMPAL DE BYVAL COMO INTEGER, NOMBRE DE LA ROITO BYVAL COMO STRING)

    43 Mouse \u003d The House

    44 MCURTEMP \u003d TEMP

    45 MNAME \u003d nombre de habitación

    46 Sub. Sub.

    47 PUBLIC Sub CheckTempinomage ()

    48 ChangeTeMperatura ()

    49 Sub. Sub.

    50 Sub Changetemperatura privada ()

    51 intento.

    52 si mhouse.houseetemp< mHouse.MAX_TEMP - 5 Then

    53 hilo.SLEEP (200)

    54 Mouse.HouseEmp + - 5

    55 console.writeline ("am in" & me.mname & _

    56 ".current la temperatura es" & mouse.houseemp)

    57. Elelf mhouse.houseeemp< mHouse.MAX_TEMP Then

    58 hilo.SLEEP (200)

    59 Mouse.HouseEmp + \u003d 1

    60 console.writeline ("am in" & me.mname & _

    61 ". Temperatura .Current es" & mouse.houseemp)

    62 de lo demás.

    63 console.writeline ("am in" & me.mname & _

    64 ".current la temperatura es" & mouse.houseemp)

    65 "No hagas nada, temperatura normal.

    66 fin si

    67 Catch Tae como ThreadlntruptException

    68 "La espera pasiva fue interrumpida.

    69 Catch E como excepción

    70 "Otras excepciones

    71 fin de intento.

    72 Sub.

    73 clase final

    Higo. 10.6. Problemas de multithreading

    El procedimiento principal principal (líneas 4-7) crea una "casa" con diez "habitaciones". Clase de la casa establece la temperatura máxima de 75 grados Fahrenheit (aproximadamente 24 grados Celsius). En las líneas 13-28, se determina un diseñador bastante complicado de la casa. La clave para entender el programa son líneas 18-27. La fila 20 crea otro objeto de habitación, mientras que el constructor se transmite al objeto de la casa para que el objeto de la habitación pueda atraerlo si es necesario. Las filas 21-23 lanzan diez hilos para ajustar la temperatura en cada habitación. La clase de la habitación se define en líneas 38-73. Casa Coxpa Objeto Enlaceen la variable de mural en el diseñador de la clase de la habitación (línea 43). El código de control de la comprobación y la temperatura (cadena 50-66) se ve simple y natural, pero, ¡pero, ya que pronto se asegurará de que sea impresionante! Tenga en cuenta que este código está adjunto en la unidad de prueba, ya que el método de suspensión se usa en el programa.

    Es poco probable que alguien esté de acuerdo en vivir a una temperatura de 105 grados Fahrenheit (40.5 24 grados Celsius). ¿Qué sucedió? El problema está relacionado con la siguiente línea:

    Si mhouse.houseetemp< mHouse.MAX_TEMP - 5 Then

    Y lo siguiente ocurre: primero, la temperatura comprueba la secuencia 1. Ve a que la temperatura es demasiado baja y la eleva en 5 grados. Desafortunadamente, antes de aumentar la temperatura, el flujo 1 se interrumpe y el control se transmite el flujo 2. El flujo 2 comprueba la misma variable que aún no se ha cambiadohilo 1. Por lo tanto, la corriente 2 también está preparada para elevar una temperatura de 5 grados, pero no tiene tiempo para hacerlo y también entra en un estado de espera. El proceso continúa hasta que la corriente 1 se activa y no cambia al siguiente equipo: aumentar la temperatura en 5 grados. El aumento se repite cuando se activan los 10 transmisiones, y los residentes de la casa tendrán que ser malos.

    Resolución de problemas: Sincronización

    En el programa anterior, surge una situación cuando el resultado de la operación del programa depende del procedimiento para realizar flujos. Para deshacerse de él, debe asegurarse de que los comandos tipo

    Si mhouse.houseetemp< mHouse.MAX_TEMP - 5 Then...

    totalmente realiza la corriente activa antes de que se interrumpa. Esta propiedad se llama atomatd -el bloque de código debe ser realizado por cada corriente sin interrumpir, como una unidad atómica. Un grupo de equipos combinados en una unidad atómica no puede ser interrumpida por el programador de flujo antes de que se complete. En cualquier lenguaje de programación multithreado, hay formas de proporcionar atomicidad. En VB .NET, es más fácil usar el comando sinclock cuando se transmite la variable del objeto. CAMBIE EL PROCEDIMIENTO DE CAMBIOTEMENTERIFICO DEL EJEMPLO ANTERIOR, CAMBIOS PEQUEÑOS y el programa funcionará normalmente:

    Subcetemperatura privada () Sincronización ()

    Intentar.

    Si mhouse.houseetemp< mHouse.MAXJTEMP -5 Then

    Hilo.SLEEP (200)

    mhouse.houseetemp + \u003d 5

    Console.writeline ("am in" & me.mname & _

    "Temperatura. Corriente es" & mouse.houseemp)

    El mismo

    mhouse.houseeemp.< mHouse. MAX_TEMP Then

    Hilo.sleep (200) mhouse.houseetemp + \u003d 1

    Console.writeline ("am in" & me.mname & _ ".current la temperatura es" & mouse.hometemp.

    Console.writelinec "am in" & me.mname & _ ".current la temperatura es" & mouse.houseemp)

    "No hagas nada, la temperatura es normal.

    Termina si la corbata de captura como la excepción.

    "La espera pasiva fue interrumpida la captura E como excepción

    "Otras excepciones

    Intento final.

    Sincronización final.

    Sub. Sub.

    El código de bloque de sincronización es atómicamente. El acceso a él desde todos los demás flujos se cerrará hasta que el primer hilo retire el bloqueo con el comando de Sincronización de extremo. Si el flujo en el bloque sincronizado cambia a la expectativa pasiva, el bloqueo se guarda hasta la interrupción o la reanudación del flujo.

    El uso correcto del comando SINCLOCK proporciona seguridad de transmisión de su programa. Desafortunadamente, el abuso de sincronización afecta negativamente el rendimiento. La sincronización del código en un programa multi-roscado reduce la velocidad de su funcionamiento varias veces. Sincronice solo el código más necesario y retire la cerradura lo antes posible.

    Las colecciones básicas son inseguras en aplicaciones multiprespontes, pero V.NET Framework incluye versiones de futuros y seguras de la mayoría de las clases de colecciones. En estas clases, el código de métodos potencialmente peligrosos son los bloques de sincronización. Las versiones seguras de flujo de las clases de colecciones deben usarse en programas múltiples en los que surgen la amenaza de integridad de los datos.

    Queda por mencionar que con la ayuda del comando sinclock, las variables condicionales se implementan fácilmente. Esto requerirá sincronizar solo la entrada en la propiedad lógica general, accesible para leer y escribir, como se realiza en el siguiente fragmento:

    Condicionario de clase pública.

    Locker compartido privado como objeto \u003d nuevo objeto ()

    Mok compartido privado como Boolean Shared

    Propiedad theconditionVariable () como boolean

    Obtener.

    Devolver Mok.

    Fin Get.

    Conjunto (Valor Byval como Sincronización Booleano) (Locker)

    mok \u003d valor.

    Sincronización final.

    Conjunto final.

    Propiedad final.

    Clase final

    Clase de Sincronización y Monitoreo del Equipo

    El uso del comando sinclock se asocia con algunas sutilezas que no se han manifestado en los ejemplos simples anteriores. Por lo tanto, se juega un papel muy importante seleccionando el objeto de sincronización. Intente ejecutar el programa anterior con el comando SINCLOCK (ME) en lugar de Sincronización (MUSHER). ¡La temperatura aumenta por encima del valor de umbral!

    Recuerde que el comando sinclock produce sincronización por objetotransmitido como parámetro, y no por el fragmento del código. El parámetro de sinclock reproduce la función de la puerta para apelar al fragmento sincronizado de otros hilos. El comando SINCLOCK (ME) en realidad abre varias "puertas" diferentes, y esto es exactamente lo que intentó evitar usar la sincronización. Moralidad:

    Para proteger los datos comunes en una aplicación multithreaded, el comando de sinclock debe sincronizarse por un objeto.

    Dado que la sincronización se asocia con un objeto específico, en algunas situaciones, hay un bloqueo involuntario de otros fragmentos. Supongamos que tiene dos métodos de primer y segundo sincronizado, y ambos métodos se sincronizan a través del objeto Biglock. Cuando el flujo 1 ingresa al primer método y captura Biglock, ningún flujo puede entrar en el segundo método, porque el acceso a él ya está limitado al flujo 1.

    La funcionalidad del comando sinclock se puede ver como un subconjunto de la funcionalidad de la clase de monitor. La clase Monitor tiene capacidades de configuración avanzadas, y con él, puede resolver tareas de sincronización no triviales. El comando sinclock es un análogo aproximado de los métodos de Moni Tor Class EXI TR:

    Intentar.

    Monitor.enter (theObject) finalmente

    Monitor.exit (theObject)

    Intento final.

    Para algunas operaciones estándar (aumento / disminución de la variable, el intercambio de los contenidos de dos variables) v.net marco es proporcionado por la clase interbloqueada, los métodos de los cuales se realizan por estas operaciones a nivel atómico. Usando la clase interbloqueada, estas operaciones se realizan mucho más rápido que usar el comando sinclock.

    Bloqueo mutuo

    En el proceso de sincronización, el bloqueo está instalado para objetos, no fluir, por lo que cuando se usa diferenteobjetos para bloquear diferentelos fragmentos de código en los programas a veces surgen errores muy no triviales. Desafortunadamente, en muchos casos, la sincronización es simplemente inaceptable a la sincronización, ya que conducirá a un bloqueo demasiado frecuente de arroyos.

    Considerar la situación bloqueo mutuo(Punto muerto) en la forma más sencilla. Imagina dos programadores en la mesa de la cena. Desafortunadamente, para dos solo tienen un cuchillo y un tenedor. Si asumimos que el cuchillo y la horquilla son necesarios para la comida, son posibles dos situaciones:

    • Un programador tiene tiempo para tomar un cuchillo con un tenedor y se acepta para la comida. Satisfecho, establece el dispositivo de comedor, y luego pueden tomar otro programador.
    • Un programador toma el cuchillo, y el otro es un tapón. Ninguno puede comenzar la comida si el otro no da su dispositivo.

    En un programa multi-roscado, se llama una situación de este tipo. bloqueo mutuo.Dos métodos son sincronizados por diferentes objetos. El flujo A captura el objeto 1 y ingresa el fragmento de un programa protegido por este objeto. Desafortunadamente, requiere acceso al código protegido por otro bloque de bloqueo de sincronización con otro objeto de sincronización. Pero antes de que tenga tiempo para ingresar un fragmento, sincronizado por otro objeto, incluye un flujo y captura este objeto. Ahora, el flujo y no puede entrar en el segundo fragmento, el flujo no puede entrar en el primer fragmento, y ambas flujos están condenados a la espera infinita. Ningún arroyo puede continuar funcionando, porque el objeto que es necesario para esto no será lanzado.

    El diagnóstico de bloqueo mutuo se ve obstaculizado por el hecho de que pueden ocurrir en casos relativamente raros. Todo depende de qué orden el planificador asignará el tiempo de procesador. Es posible que, en la mayoría de los casos, los objetos de sincronización se capturen de una manera que no conduzca al bloqueo mutuo.

    A continuación se muestra la implementación de la situación descrita de bloqueo mutuo. Después de una breve discusión de los momentos más fundamentales, mostraremos cómo identificar la situación del bloqueo mutuo en la ventana de las transmisiones:

    1 opción estricta en

    2 Sistema de importaciones.

    Módulo de 3 módulos

    4 SUB PRINCIPAL ()

    5 Dim Tom como nuevo programador ("Tom")

    6 Dim Bob como nuevo programador ("Bob")

    7 Dim AthReadStart como nuevo hilo (dirección de Tom.Eat)

    8 Dim Athread como nuevo hilo (AthReadStart)

    9 athread.name \u003d "Tom"

    10 Dim Bthradstartst como nuevo ThreadStartTaddressof Bob.Est)

    11 DIM BRTHEAD COMO HILO NUEVO (BTHTRADSTART)

    12 bthread.name \u003d "bob"

    13 Athread.start ()

    14 bthread.start ()

    15 Sub. Sub.

    16 módulo final.

    17 Tenedor de clase pública

    18 Privado compartido MForkavaitable como booleano \u003d verdadero

    19 Mowner compartido privado como cadena \u003d "Nadie"

    20 PROPIEDADES DE PROPIEDAD PROPIEDAD PROPIEDADES SUNSIL () TAN STRING

    21 Get.

    22 RENDER MOWNER.

    23 Get Get.

    24 propiedad final.

    25 PUBLIC Sub GrabforkTbyVal A como programador)

    26 console.writel_ine (hilo.currentthread.name & _

    "Tratando de agarrar el tenedor".)

    27 console.writeline (me.ownsutensil & "tiene el tenedor"). .

    28 Monitor.Enter (ME) "SINCLOCK (AFORK)"

    29 si mforkavailable then

    30 a.hasfork \u003d verdadero

    31 MOWNER \u003d A.MYNAME

    32 MforkAvailable \u003d. Falso

    33 console.writeline (a.myname & "acaba de conseguir el tenedor.waiting")

    34 intento.

    Hilo.SLEEP (100) Catch e como consola de excepción. Embalanza (E.Stacktrace)

    Intento final.

    35 final si

    36 monitor.exit (yo)

    Sincronización final.

    37 Sub.

    38 clase final

    39 Cuchillo de clase pública

    40 MQ KKNIFEAPORTE COMPARTIDO PRIVADO COMO BOOLEAN \u003d VERDADERO

    41 Mowner compartido privado como cadena \u003d "Nadie"

    42 Propiedad privada Readonly PoseSunsi1 () como cadena

    43 Get.

    44 Mowner de retorno.

    45 Get Get.

    46 propiedad final.

    47 PUBLIC Sub GrabknifetByVal a como programador)

    48 console.writeline (hilo.currentthread.name & _

    "Tratando de agarrar el cuchillo".)

    49 console.writeline (me.ownsutensil & "tiene el cuchillo")

    50 Monitor.Enter (ME) "SINCLOCK (ANKNIFE)"

    51 Si mkkeApablea

    52 MKKNIFEAVIBLE \u003d FALSO

    53 a.hasknife \u003d verdadero

    54 MOWNER \u003d A.MYNAME

    55 console.writeline (a.myname & "acaba de conseguir el cuchillo.waiting")

    56 intento.

    Hilo.SLEEP (100)

    Catch e como excepción

    Console.writeline (e.stacktrace)

    Intento final.

    57 final si

    58 monitor.exit (yo)

    59 Sub. Sub.

    60 clase final

    61 programador de clase pública

    62 MNAME privado como cadena

    63 MFork compartido privado como tenedor

    64 MMknife compartido privado como cuchillo

    65 Privado MHasknife como Boolean

    66 MHASFORK privado como booleano

    67 subvenciones compartidas ()

    68 MFork \u003d nuevo tenedor ()

    69 MKKNIFE \u003d NUEVO CUCHILLO ()

    70 Sub. Sub.

    71 PUBLIC Sub New (Byval Thale como cadena)

    72 MNAME \u003d THEENE

    73 Sub.

    74 Propiedad Readonal pública MyName () como cadena

    75 Get.

    76 Regresar MNAME.

    77 Get Get.

    78 propiedad final.

    79 propiedad pública haknife () como booleano

    80 Get.

    81 VOLVER MHASKNIFE.

    82 Get Get.

    83 Set (valor byval como booleano)

    84 MHasknife \u003d Valor

    85 conjunto de final.

    86 propiedad final.

    87 propiedad pública hostfork () como booleano

    88 Get.

    89 Regreso MHASFork.

    90 Get Get.

    91 conjunto (valor byval como booleano)

    92 MHASFork \u003d Valor

    93 conjunto final.

    94 propiedad final.

    95 Public Sub Coma ()

    96 Hacer hasta mí .Hasknife y yo.hastork

    97 console.writeline (hilo.currentthread.name & "está en el hilo")

    98 si rnd ()< 0.5 Then

    99 mfork.grabfork (yo)

    100 de lo demás.

    101 Mkknife.Grabnife (yo)

    102 final si

    103 bucle.

    104 msgbox (me.myname & "puede comer!")

    105 Mkknife \u003d nuevo cuchillo ()

    106 MFork \u003d nuevo tenedor ()

    107 Sub. Sub.

    108 clase final

    El principal procedimiento principal (cadena 4-16) crea dos instancias de la clase del programador y luego comienza a dos hilos para realizar el método crítico de la clase de programador Coma (filas 95-108) que se describen a continuación. El procedimiento principal establece los nombres de los flujos y los entra; Probablemente, todo lo que sucede es claro y sin comentarios.

    El código de la horquilla de clase (cadenas 17-38) se ve más interesante (la clase de cuchillo similar se define en las líneas 39-60). En las líneas 18 y 19, se establecen los valores de los campos comunes, que se pueden encontrar si el tapón está disponible en este momento, y si no, quién lo usa. Readonly-PROPIETEUSI1 (LÍNEAS 20-24) está destinado a la transferencia de información más simple. El lugar central en la clase de la horquilla ocupa la "captura de la captura de la bifurcación" Grabador, definida en las líneas 25-27.

    1. Las filas 26 y 27 se muestran simplemente en la información de depuración de la consola. Básicamente, el código del método (cadenas 28-36) El acceso a la horquilla está sincronizado por objeto NEcinturón yo Dado que solo se usa un enchufe en nuestro programa, la sincronización me garantiza que dos flujos no puedan capturarlo simultáneamente. El "comando" de manga "P (en el bloque de inicio en la línea 34) imita el retraso entre el agarre de la horquilla / cuchilla y el comienzo de los alimentos. Tenga en cuenta que el comando de sueño no elimina el bloqueo de los objetos y solo se acelera ¡La aparición del bloqueo mutuo!
      Sin embargo, el código de clase programador (cadenas 61-108) representa el mayor interés. En las líneas 67-70, se determina un diseñador general, lo que garantiza la presencia de un solo tenedor y cuchillo en el programa. El código de propiedad (CAVING 74-94) es simple y no requiere comentarios. Lo más importante sucede en el método de comer realizado por dos flujos separados. El proceso continúa en el ciclo hasta que cualquier hilo captura el tapón junto con la cuchilla. En las líneas 98-102, el objeto captura aleatoriamente la horquilla / cuchilla utilizando la llamada RND: esto es exactamente lo que causa el bloqueo mutuo. Ocurre lo siguiente:
      El flujo que realiza el método de come objeto está activado y entra en el ciclo. Captura el cuchillo y entra en un estado de espera.
    2. Una corriente que realiza el método de comer del objeto Bob se activa y entra en el ciclo. No puede capturar el cuchillo, pero captura el enchufe y entra en el estado de espera.
    3. El flujo que realiza el método de come objeto está activado y entra en el ciclo. Intenta capturar el enchufe, sin embargo, el enchufe ya está capturado por el objeto Bob; El hilo va al estado de espera.
    4. Una corriente que realiza el método de comer del objeto Bob se activa y entra en el ciclo. Él está tratando de capturar el cuchillo, pero el cuchillo ya está capturado por el objeto uno; El hilo va al estado de espera.

    Todo esto continúa hasta el infinito, ante nosotros la situación típica del bloqueo mutuo (intente ejecutar el programa, y \u200b\u200bse asegurará de que no sea posible comer para que nadie).
    En la aparición de bloqueo mutuo se puede encontrar en la ventana de las corrientes. Ejecute el programa e interrumpirlo con Ctrl + Break Keys. Encienda la variable ME en la ventana de vista y abra la ventana de Streams. El resultado se ve aproximadamente como se muestra en la FIG. 10.7. De la figura está claro que el flujo de Bob capturó el cuchillo, pero no tiene horquillas. Haga clic con el botón derecho en la ventana de Streams en la cadena. Y seleccione el comando Cambiar al enlace en el menú contextual. La ventana de visualización muestra que la corriente es un tenedor, pero no hay cuchillo. Por supuesto, esto no es un cien por ciento de prueba, pero ese comportamiento al menos lo hace imposible.
    Si no es posible una opción con sincronización por un objeto (como en el programa con un aumento en el Empener en la casa), para prevenir los bloqueos mutuos, puede numerar los objetos de sincronización y siempre los capturarlos en constante. Continuaremos una analogía con programadores de comensales: si el flujo siempre toma el cuchillo primero, y luego la horquilla, no habrá problemas con el bloqueo mutuo. La primera corriente, capturando el cuchillo, puede comer normalmente. Traducido en el idioma de los flujos de software, esto significa que la captura del objeto 2 es posible solo bajo la condición de la captura previa del objeto 1.

    Higo. 10.7. Análisis del bloqueo mutuo en la ventana de la corriente.

    En consecuencia, si elimina la llamada RND en la línea 98 y reemplácela con un fragmento

    mfork.grabfork (yo)

    mkknife.grabknife (yo)

    ¡El bloqueo mutuo desaparece!

    Colaboración con datos como se crean.

    En las aplicaciones de múltiples hilos, la situación se encuentra a menudo cuando las corrientes no solo funcionan con datos generales, sino que también esperan su apariencia (es decir, el flujo 1 debe crear datos antes de que el flujo 2 pueda usarlos). Dado que los datos son comunes, el acceso a ellos debe ser sincronizado. También es necesario proporcionar fondos para las alertas de las transmisiones en espera sobre la aparición de datos listosizados.

    Esta situación se suele llamar. problema "Proveedor / consumidor".El arroyo está tratando de referirse a los datos que aún no están, por lo que debe transferirse a otra transmisión, creando los datos necesarios. El problema se resuelve mediante el código del siguiente tipo:

    • El flujo 1 (consumidor) está activado, ingrese el método sincronizado, busca datos, no los encuentra y entra en un estado de espera. Progresocalino Debe quitar la cerradura para no interferir con el trabajo del proveedor.
    • El flujo 2 (proveedor) ingresa al método sincronizado lanzado por Stream 1, crealos datos para la flujo 1 y de alguna manera notifique el flujo 1 en la disponibilidad de datos. Luego, elimina la cerradura para que el flujo 1 pueda procesar nuevos datos.

    No intente resolver este problema con una activación constante del flujo 1 con un estado válido de la variable condicional, el valor del cual está establecido por el flujo 2. Esta solución afectará seriamente la velocidad de su programa, ya que en la mayoría de los casos El flujo 1 se activará sin ninguna razón; Un flujo 2 se moverá a la espera, a menudo que no tendrá tiempo para crear datos.

    La comunicación comunicativa / consumidor se encuentra a menudo a menudo, por lo tanto, las primitivas especiales se crean en las bibliotecas de clases de programación multiprespontes para tales situaciones. V.net Estas primitivas se llaman espera y pulsos 1 y forman parte de la clase de monitor. La Figura 10.8 explica la situación que vamos a programar. El programa organiza tres colas de flujo: cola de espera, cola de bloqueo y cola de ejecución. El planificador de flujo no resalta el tiempo del procesador en la cola de espera. Para que la corriente tenga tiempo, debe moverse a la cola de ejecución. Como resultado, la aplicación de la solicitud se organiza mucho más eficientes que con el encuesta habitual de la variable condicional.

    El pseudocódigo del Idioma del consumidor de datos está formulado como:

    "Entrada al bloque sincronizado del siguiente tipo.

    Mientras no hay datos

    Ir a la cola de espera

    Círculo.

    Si los datos son, procesarlos.

    Deja un bloque sincronizado.

    Inmediatamente después de ejecutar el comando de espera, la secuencia está suspendida, se retira el bloqueo y la rosca va a la cola de espera. Al eliminar el bloqueo, el flujo ubicado en la cola de ejecución obtiene la capacidad de trabajar. Con el tiempo, uno o más hilos bloqueados crearán los datos necesarios para el trabajo del flujo en la cola de espera. Dado que la verificación de datos se lleva a cabo en el ciclo, la transición al uso de datos (después del ciclo) ocurre solo en presencia de datos listos para su procesamiento.

    El pseudocódigo del Idioma del proveedor de datos se ve así:

    "Entrada a un bloque de tipo sincronizado.

    Mientras que los datos no son necesarios

    Ir a la cola de espera

    De lo contrario hacer datos

    Después de que aparezcan los datos preparados, llame a Pulse-PulSeall.

    para mover uno o más hilos desde la cola de bloqueo en la cola de ejecución. Deje el bloque sincronizado (y regrese a la cola de ejecución)

    Supongamos que nuestro programa simula a una familia con un padre que gana dinero y un niño que gasta este dinero. Cuando el dinero cumtienes que esperar la llegada de la nueva cantidad. La implementación del software de este modelo se ve así:

    1 opción estricta en

    2 Sistema de importaciones.

    Módulo de 3 módulos

    4 SUB PRINCIPAL ()

    5 Dim Thisfamily como nueva familia ()

    6 TheFamily.SartltsLife ()

    7 subvención final

    8 Fijó FJODULO.

    9

    10 familia de clase pública

    11 Privado MMONEY COMO INTEGER

    12 privado Mweek como entero \u003d 1

    13 Sub Startltsltslife ()

    14 Dim AthReadStart como nuevo ThreadStaruAddressof me.produce)

    15 Dim BthradStart como nuevo ThreadStaruAddressof Me.Consume)

    16 Dim Athread como nuevo hilo (AthReadStart)

    17 DIM BRTHEAD como nuevo hilo (BTHTRETSTART)

    18 Athread.Name \u003d "Produce"

    19 athread.start ()

    20 bthread.name \u003d "consume"

    21 BRTHEAD. COMIENZO ()

    22 Subs de final

    23 propiedad pública Theweek () como entero

    24 Get.

    25 regreso Mweek

    26 Get Get.

    27 Set (valor byval como entero)

    28 Mweek - Valor

    29 conjunto final.

    30 propiedad final.

    31 propiedad pública Ourmoney () como entero

    32 Get.

    33 retorno mmoney

    34 Get Get.

    35 Set (valor byval como entero)

    36 mmoney \u003d valor

    37 conjunto final.

    38 propiedad final.

    39 Sub Producto Público ()

    40 hilo.SLEEP (500)

    41 hacer.

    42 monitor.enter (yo)

    43 Do mientras me.ourmoney\u003e 0

    44 monitor.wait (yo)

    45 bucle.

    46 me.ourmoney \u003d 1000

    47 monitor.pulsall (yo)

    48 monitor.exit (yo)

    49 bucle.

    50 subst.

    51 Sub Consumo Público ()

    52 MsgBox ("Estoy en el hilo de consumo")

    53 hacer.

    54 monitor.enter (yo)

    55 Do mientras me.ourmoney \u003d 0

    56 monitor.wait (yo)

    57 bucle.

    58 console.writeline ("Querido padre, acabo de pasar todo Yur" & _

    dinero en la semana "& theweek)

    59 Theweek + \u003d 1

    60 SI THEWEEK \u003d 21 * 52 LESYE SYSTEM.Environment.exit (0)

    61 me.ourmoney \u003d 0

    62 monitor.pulsall (yo)

    63 monitor.exit (yo)

    64 bucle.

    65 Sub.

    66 clase final

    El método StartltsLife (Filas 13-22) se prepara para el inicio del producto y consumo de flujos. Lo más importante sucede en los flujos de productos (cadenas 39-50) y consumen (cadenas 51-65). El procedimiento de Sub Produce comprueba la disponibilidad de dinero, y si hay dinero, va a la cola de espera. De lo contrario, el padre genera dinero (línea 46) y notifica a los objetos en la cola de espera sobre cómo cambiar la situación. Tenga en cuenta que el pulso de pulso, toda la llamada entra en vigor cuando se elimina el comando monitor.exit. A la inversa, el procedimiento Sub Consumo verifica la disponibilidad de dinero, y si no hay dinero, notifica a este padre en espera. La fila 60 simplemente completa el programa después de 21 años condicional; Sistema de llamadas. Environment.exit (0) es un análogo de .NET del comando final (el comando final también se admite, pero a diferencia del sistema. Medio ambiente. Salir No le permite devolver el código de finalización del sistema operativo).

    Los hilos traducidos en la cola de espera deben ser lanzados por otras horas de su programa. Es por esta razón que preferimos usar PULSEALL en lugar de pulso. Dado que no se sabe de antemano, lo que precisamente se activará el flujo al llamar a Pulse 1, con un número relativamente pequeño de hilos en la cola con el mismo éxito, puede llamar a PULSEALL.

    MultiPhreading en programas gráficos

    Nuestra discusión de MultiShreading en aplicaciones con una interfaz gráfica comenzará con un ejemplo que explica por qué se necesita multithreading en aplicaciones gráficas. Cree un formulario con dos botones de inicio y cancele (BTNCANCEL), como se muestra en la FIG. 10.9. Cuando presiona el botón Inicio, se crea una clase que contiene una línea aleatoria de 10 millones de caracteres y un método para contar las letras de la letra "E" en esta larga cadena. Preste atención al uso de una clase StringBuilder que mejora la eficiencia de crear líneas largas.

    Paso 1

    Flow 1 Notas que no hay datos para ello. Causa esperar, elimina la cerradura y gira la cola de espera.



    Paso 2.

    Cuando se retira el bloqueo, la secuencia 2 o la corriente 3 sale de la cola de bloqueo y ingresa al bloque sincronizado al configurar el bloqueo

    Lado

    Supongamos que la corriente 3 entra en el bloque sincronizado, crea datos y llama a pulso de pulso todo.

    Inmediatamente después de que salga del bloqueo de bloques y eliminación, el flujo 1 se mueve a la cola de ejecución. Si el flujo 3 llama pluse, en la cola de ejecución, solo uno pasael hilo al llamar a la placa todo a la cola de ejecución va todas las corrientes.



    Higo. 10.8. Problema "Proveedor / consumidor"

    Higo. 10.9. MultiPhreading en una aplicación simple con una interfaz gráfica.

    Imports System.Text

    Personajes de clase pública.

    Privado m_data como StringBuilder

    Private MJongong, M_Count como entero

    Sub nuevo público (Byval n como entero)

    m_length \u003d n -1

    m_data \u003d nuevo StringBuilder (M_Length) Maestring ()

    Sub. Sub.

    SUB PRIGO PRINCIPAL ()

    Dim I como entero

    Dim Myrnd como nuevo aleatorio ()

    Para i \u003d 0 a m_length

    "Generar un número aleatorio de 65 a 90,

    "Convertirlo a una letra mayúscula

    "Y adjuntar al objeto StringBuilder

    m_data.append (Chr (Myrnd.Next (65.90)))

    próximo

    Sub. Sub.

    Sub StartCount público ()

    GETEES ()

    Sub. Sub.

    Sub Gteees privados ()

    Dim I como entero

    Para i \u003d 0 a m_length

    Si M_DATA.CHARS (i) \u003d CCHAR ("E") entonces

    m_count + \u003d 1

    Termina si a continuación

    m_countdone \u003d verdadero.

    Sub. Sub.

    Público listonalmente

    Propiedad getcount () como entero obtener

    Si no (m_countdone) entonces

    Devuelve M_Count.

    Terminara si

    Fin Get Fin de propiedad

    Público listonalmente

    Propiedad Isdone () como Boolean Get

    Regreso.

    m_countdone

    Fin Get.

    Propiedad final.

    Clase final

    Con dos botones en el formulario, se asocia un código muy simple. El procedimiento BTN-START_CLICK crea una instancia de la clase anterior de los personajes aleatorios, encapsulando una cadena con 10 millones de caracteres:

    Sub BTnstart_Click privado (remitente BYVAL como SYSTEM.OBJECT.

    Byval E como System.Eventargs) Maneja BTNSTART.HIGHT

    Dim RC como nuevos personajes aleatorios (10000000)

    Rc.startcount ()

    MsgBox ("El número de ES es" & rc.getcount)

    Sub. Sub.

    El botón CANCELAR Muestra la ventana del mensaje:

    Sub Btncancel_Click privado (remitente BYVAL como SYSTEM.OBJECT._

    Byval E como System.Eventargs) Maneja a Btncancel.Haga clic

    MsgBox ("Cuentan interrumpido!")

    Sub. Sub.

    Cuando inicie el programa y presione el botón Inicio, resulta que el botón Cancelar no responde a las acciones del usuario, ya que el ciclo continuo no permite que el botón maneje el evento recibido. En los programas modernos, esto es inaceptable!

    Dos soluciones son posibles. La primera opción, bien familiarizada en las versiones anteriores de VB, se realiza sin multithreading: el ciclo se convierte en la llamada de los propulsores. V.net Este comando se ve así:

    Aplicación.devents ()

    En nuestro ejemplo, definitivamente es indeseable, ¿quién querrá ralentizar el programa diez millones de llamadas a los propentos? Si, en su lugar, asigne el ciclo en un flujo por separado, el sistema operativo cambiará entre hilos y el botón CANCELAR RETENDARá el rendimiento. Las ventas con una corriente separada se muestran a continuación. Para demostrar claramente que funciona el botón CANCELAR, cuando se lo presiona, simplemente completamos el programa.

    Paso siguiente: Mostrar botón de cuenta

    Supongamos que decidiste mostrar fantasía creativa y darte una vista de formulario que se muestra en la FIG. 10.9. Tenga en cuenta que: el botón Show Count todavía no está disponible.

    Higo. 10.10. Forma con un botón bloqueado

    Se supone que un hilo separado calcula y desbloquea el botón inaccesible. Por supuesto, esto se puede hacer; Además, tal tarea ocurre con bastante frecuencia. Desafortunadamente, no podrá actuar la forma más obvia: organizar una conexión de transmisión secundaria con una corriente de interfaz gráfica, guardar un enlace al botón ShowSount en el constructor, o incluso usando un delegado estándar. En otras palabras, nuncano utilice la opción a continuación. erróneolas filas están resaltadas en negrita).

    Personajes de clase pública.

    Private M_0ATA como StringBuilder

    Privado m_countdone como booleano

    Private MJongong. M_Count como entero.

    Private M_Button como Windows.Forms.Button

    Sub nuevo público (BYVA1 N como entero, _

    BYVAL B como Windows.Forms.Button)

    m_length \u003d n - 1

    m_DATA \u003d Nuevo StringBuilder (MJongong)

    m_BUTTON \u003d B FESTESTRING ()

    Sub. Sub.

    SUB PRIGO PRINCIPAL ()

    Dim I como entero

    Dim Myrnd como nuevo aleatorio ()

    Para i \u003d 0 a m_length

    m_data.append (Chr (Myrnd.Next (65. 90)))

    próximo

    Sub. Sub.

    Sub StartCount público ()

    GETEES ()

    Sub. Sub.

    Sub Gteees privados ()

    Dim I como entero

    Para i \u003d 0 a mjongitud

    Si M_DATA.CHARS (i) \u003d CCHAR ("E") entonces

    m_count + \u003d 1

    Termina si a continuación

    m_countdone \u003d verdadero.

    m_button.enabled \u003d verdadero.

    Sub. Sub.

    Público listonalmente

    Propiedad getcount () como entero

    Obtener.

    Si no (m_countdone) entonces

    Tirar una nueva excepción ("Cuenta aún no terminada") otra cosa)

    Devuelve M_Count.

    Terminara si

    Fin Get.

    Propiedad final.

    Propiedad lódica pública Isdone () como Boolean

    Obtener.

    Devolver m_countdone

    Fin Get.

    Propiedad final.

    Clase final

    Es probable que, en algunos casos, este código funcione. Sin emabargo:

    • La interacción de la corriente secundaria con un flujo que crea una interfaz gráfica no se puede organizar obviomedio.
    • Nuncano cambie los artículos en gráficos de otras transmisiones de software. Todos los cambios deben ocurrir solo en la corriente que creó la interfaz gráfica.

    Si crías estas reglas, nosotros nosotros garantizamosque en sus programas de gráficos multi-roscados ocurrirán errores delgados y esquivos.

    No será posible organizar la interacción de los objetos con el uso de eventos. Un trabajador de eventos 06 se realiza en el mismo hilo en el que se ha producido una llamada RaiseEvent, por lo que los eventos no lo ayudarán.

    Sin embargo, el sentido común sugiere que en las aplicaciones gráficas debe haber medios de modificación de elementos de otra corriente. V.NET Framework Hay un método seguro de flujo para llamar a los métodos de las aplicaciones GUI de otra corriente. Para este propósito, el tipo especial de delegados del método de invocador se utiliza desde el espacio de nombres del sistema. Formas. El siguiente fragmento proporciona una nueva opción del método de GETEES (las líneas modificadas se resaltan en negrita):

    Sub Gteees privados ()

    Dim I como entero

    Para i \u003d 0 a m_length

    Si M_DATA.CHARS (i) \u003d CCHAR ("E") entonces

    m_count + \u003d 1

    Termina si a continuación

    m_countdone \u003d verdadero intento

    Dim Mylnvoker como New MethodlnVoker (Dirección de UpdateButton)

    myInvoker.Invoke () Catch E como ThreadlntruptException

    "Falla

    Intento final.

    Sub. Sub.

    Sub UpdationButton ()

    m_button.enabled \u003d verdadero.

    Sub. Sub.

    El acceso a la interpotión al botón no se lleva a cabo directamente, sino a través del método Invocoker. .NET Framework garantiza que esta opción sea segura para los arroyos.

    ¿Por qué con la programación multi-roscada, surgen tantos problemas?

    Ahora que ha recibido una idea de la programación multithreadizada y los posibles problemas relacionados con ella, decidimos que al final de este capítulo sería apropiado responder a la pregunta hecha en el titular de la subsección.

    Una de las razones es que la multiplicidad es no lineal, y estamos acostumbrados a un modelo de programación lineal. Al principio, es difícil acostumbrarse a la idea de que la ejecución del programa se puede interrumpir al azar, y el control se transmitirá a otro código.

    Sin embargo, hay otra razón más fundamental: hoy en día, los programadores están muy raramente programados en un ensamblador o al menos explorando los resultados de desmontaje del compilador. De lo contrario, sería mucho más fácil para ellos acostumbrarse al pensamiento de que un equipo de lenguaje de alto nivel (como VB .NET) puede corresponder a docenas de instrucciones de ensamblador. El flujo se puede interrumpir después de cualquiera de estas instrucciones, y por lo tanto, y en medio del comando de alto nivel.

    Pero esto no es todo: los compiladores modernos optimizan la velocidad de los programas, y el equipo informático puede interferir en el proceso de administración de la memoria. Como resultado, el compilador o equipo puede cambiar el procedimiento especificado en el texto de origen del programa sin su conocimiento [ Muchos compiladores optimizan las operaciones cíclicas de copia de las matrices del formulario I \u003d 0 a n: b (i) \u003d a (i): NCXT. El compilador (o incluso un dispositivo de gestión de memoria especializado) puede simplemente crear una matriz, y luego llenarla con una operación de copia en lugar de una copia múltiple de artículos individuales!].

    Esperamos que estas explicaciones lo ayuden a comprender mejor por qué la programación multinfilada genera tantos problemas, o al menos menos sorpresa a la vista de un comportamiento extraño de sus programas de múltiples roscados!

    Rueda de andrey

    Comenzando con los principios de la creación de aplicaciones multiprescritas para el entorno Marco de Microsoft .NET, mencionaremos de inmediato: aunque todos los ejemplos se dan en Visual Basic .NET, el método para crear dichos programas es generalmente el mismo para todos los idiomas de programación Que soporta .NET, incluido C #. VB se selecciona para demostrar la tecnología de crear aplicaciones multiprescritas principalmente porque las versiones anteriores de esta herramienta no proporcionaron tal oportunidad.

    Precaución: Visual Basic .NET también puede hacerlo!

    Como usted sabe, Visual Basic (a la versión 6.0 inclusive) nunca ha permitido crear componentes de software multi-roscados (EXE, ActiveX DLL y OCX). Aquí debe recordar que la arquitectura COM incluye tres modelos de transmisión diferentes: apartamento roscado de un solo hilo, STA y gratis (apartamento multi-roscado). VB 6.0 le permite crear programas para los dos primeros tipos. La opción STA proporciona un modo de pseudo-flujo: varios hilos realmente funcionan en paralelo, pero el código del programa de cada uno de ellos está protegido del acceso a él desde el exterior (en particular, las transmisiones no pueden usar los recursos compartidos).

    Visual Basic .NET ahora puede implementar el MultiPhreading gratuito en su versión actual (nativa). Más precisamente, V.Net, un modo de este tipo se admite a nivel de las bibliotecas de la biblioteca de clases comunes y el tiempo de ejecución del lenguaje común. Como resultado de VB.net, a la par con otros lenguajes de programación. Tiene acceso a estas características.

    En un momento, la comunidad de VB-Developer, que expresa insatisfacción con muchas innovaciones futuras de este idioma, reaccionó con una gran aprobación a la noticia de que será posible crear programas multi-roscados con la ayuda de la nueva versión de la herramienta (consulte "En espera Para Visual Studio .Net "," Byte / Rusia "No. 1/2001). Sin embargo, muchos expertos expresaron evaluaciones más restringidas sobre esta innovación. Aquí, por ejemplo, la opinión de Dana Appleman (Dan Appleman), un desarrollador conocido y el autor de numerosos libros para programadores de VB: "La multopezas en VB.NET se asustó de mí más que todas las demás innovaciones, y, como en Muchas nuevas tecnologías .NET, esto se explica por factores humanos en lugar de tecnológicos ... Tengo miedo de los multihumores en VB.NET, porque los programadores de VB generalmente no tienen la experiencia de diseñar y depurar aplicaciones multi-roscadas ".

    De hecho, al igual que otras herramientas de programación de bajo nivel (por ejemplo, las mismas interfaces de la API de Win), MultiPhreading gratuito, por un lado, proporciona más oportunidades para crear soluciones escalables de alto rendimiento, y, en el otro, tiene mayores demandas en El desarrollo de los desarrolladores. Además, el problema aquí se ve exacerbado por el hecho de que la búsqueda de errores en una aplicación multi-roscada es muy compleja, ya que aparecen con mayor frecuencia al azar, como resultado de una intersección específica de los procesos de computación paralelos (a menudo es imposible reproducirse tal situacion). Es por eso que los métodos de los programas de depuración tradicionales en forma de re-ejecutados en este caso generalmente no están ayudando. Y la única forma en que el uso seguro de MultiPhreading es un diseño de alta calidad de una solicitud de conformidad con todos los principios clásicos de "Programación adecuada".

    El problema con los programadores de VB también es el hecho de que, aunque muchos de ellos son profesionales bastante experimentados y son perfectamente conscientes de las piedras submarinas de MultiThreading, el uso de VB6 podría follar su vigilancia. Después de todo, acusando a VB en limitabilidad, a veces olvidamos que muchas restricciones se determinaron mediante mejores herramientas de seguridad que advierten o excluyemos errores de desarrolladores. Por ejemplo, VB6 crea automáticamente una copia separada de todas las variables globales para cada transmisión, lo que evita los posibles conflictos entre ellos. En vb.net, tales problemas se desplazan completamente en los hombros del programador. También se debe recordar que el uso de un modelo multi-roscado en lugar de un solo rosco de un solo rosco de conducir siempre a un aumento en el rendimiento del programa, el rendimiento puede incluso disminuir (incluso en sistemas multiprocesadores).

    Sin embargo, todo lo anterior no necesita ser considerado como un consejo que no se vincule a MultiShreading. Solo es necesario representarlo bien cuando se deben aplicar tales modos, y comprender que una herramienta de desarrollo más poderosa siempre coloca requisitos más altos para las calificaciones del programador.

    Tratamiento paralelo en VB6

    Por supuesto, fue posible organizar datos de procesamiento de datos pseudoalelos con VB6, pero estas oportunidades fueron muy limitadas. Por ejemplo, necesitaba hace unos años para escribir un procedimiento que suspende la ejecución del programa al número especificado de segundos (el operador de sueño correspondiente en el formulario terminado estuvo presente en Microsoft Basic / DOS). Es fácil implementar independientemente en forma del siguiente subprograma simple:

    En su desempeño, puede estar fácilmente convencido, por ejemplo, utilizando dicho código de manejo de códigos:

    Para resolver este problema en VB6, dentro del ciclo de listo. SleepVB. Los procedimientos deben retirar un comentario al acceder a la función de los propulsores, que transmite la administración del sistema operativo y devuelve la cantidad de formularios abiertos en esta aplicación VB. Pero tenga en cuenta que la salida de la ventana con el mensaje "One More Hola!", A su vez, bloquea la ejecución de toda la aplicación, incluidos los procedimientos de SleepVB.

    Usando variables globales como banderas, también puede proporcionar una finalización de emergencia del procedimiento de ejecución SleepVB. , A su vez, es el ejemplo más simple de un proceso de computación que ocupa completamente los recursos del procesador. Pero si realiza algunos cálculos útiles (y no gire en un ciclo vacío), debe tener en cuenta que la apelación a la función dévente tarda bastante en tiempo, por lo que debe realizarse a través de intervalos de tiempo suficientemente grandes.

    Para ver el soporte limitado para la computación paralela en VB6, reemplace la apelación a la función de DIEVENTES para mostrar la etiqueta:

    Etiqueta1.caption \u003d temporizador.

    En este caso, no solo no funcionará el botón Commando2, sino que incluso para 5 S no cambiará el contenido de la etiqueta.

    Para llevar a cabo un experimento más, agregue una llamada al código para comando2 (esto se puede hacer, ya que el procedimiento SleepVB es reintendeble):

    Private Sub Command2_Click () Llame a SleepVB (5) MsgBox "Otro Hola!" Sub. Sub.

    A continuación, ejecute la aplicación y haga clic en Command1, y después de 2-3 C - Command2. ¡El primer mensaje aparecerá "otro hola"!, \u200b\u200bAunque el proceso correspondiente se lanzó más adelante. La razón de esto es que las funciones de los dichos revisan solo los eventos de elementos visuales, pero no la presencia de otros flujos de computación. Además, la aplicación VB en realidad funciona en una secuencia, por lo que el control regresó al procedimiento de evento que se lanzó por última vez.

    Control de flujo V.NET

    Construyendo aplicaciones .NET MULTI-roscadas basadas en el uso de un grupo de clases de marco básico .NET que se describen por System.Trading Namespace. En este caso, la función clave pertenece a la clase de hilo, con la que se realizan casi todas las operaciones de gestión de flujo. Desde este lugar, todo el trabajo anterior con flujos pertenece a todos los medios de programación V.net, incluido C #.

    Para un primer conocimiento de la creación de flujos paralelos, crearemos una aplicación de Windows con un formulario en el que se colocará el botón ButtonStart y ButtonAbort y escribiremos el siguiente código:

    Inmediatamente me gustaría prestar atención a tres puntos. Primero, las palabras clave de importaciones se utilizan para atraer a los nombres abreviados de las clases que se describen aquí por el espacio de nombres. Lideré específicamente otra realización de las importaciones para describir el equivalente abreviado al nombre del espacio de nombres (VB \u003d Microsoft.VisualBasic), que se puede aplicar al texto del programa. En este caso, se ve inmediatamente que el objeto Temporizador se refiere a qué espacio de nombres.

    En segundo lugar, utilicé los soportes de lógica de #region para separar claramente el código escrito por mí, desde el código formado por los formularios del diseñador automáticamente (este último no se le da aquí).

    En tercer lugar, las descripciones de los parámetros de entrada de los procedimientos de eventos se eliminan específicamente (a veces serán más adelante) para no distraerse las cosas que no son importantes en este caso.

    Ejecute la aplicación y haga clic en el botón ButtonStart. Se lanzó el proceso de espera en el ciclo de un intervalo de tiempo específico, y en este caso (en contraste con un ejemplo con VB6), en una corriente independiente. Esto se garantiza fácilmente: todos los elementos de forma visual están disponibles. Por ejemplo, al hacer clic en el botón ButtonAbort, puede completar accidentalmente el proceso utilizando el método de abort (¡pero el cierre del formulario utilizando el botón Cerrar sistema no interrumpa el procedimiento!). Para mayor claridad de la dinámica del proceso, puede colocar una etiqueta en el formulario y agregar la salida de tiempo actual al ciclo de procedimiento de SleepVBNet:

    Label1.text \u003d _ "tiempo actual \u003d" & vb.timeofday

    La ejecución del procedimiento de SleepVBNet (que en este caso ya es un nuevo método de objeto) continuará, incluso si agrega el mensaje al inicio de los cálculos después de comenzar la transmisión al código ButtonStart (Fig. 1).

    Una versión más compleja, una corriente en forma de clase.

    Para llevar a cabo nuevos experimentos con hilos, cree una nueva aplicación de la consola VB, que consiste en un módulo de código principal convencional (que comienza a ejecutarse cuando se inicia la aplicación) y el módulo WorkerHradClass:

    Vamos a iniciar la solicitud creada. Aparece una ventana de consola, en la que la cadena de ejecución de los caracteres será visible, lo que demuestra el modelo del proceso de computación en ejecución (trabajador). Luego habrá una ventana de mensajes emitida por la persona que llama (principal) y, en conclusión, veremos la imagen que se muestra en la FIG. 2 (Si no está satisfecho con la velocidad del proceso simulado, retire o agregue algunas operaciones aritméticas con la variable "A" en el procedimiento de THERBERTHTHREAD).

    Tenga en cuenta que: la ventana de mensaje "Ejecute el primer hilo" se emitió a una pantalla de retardo notable, después del inicio del proceso de trabajador (en el caso del formulario descrito en el párrafo anterior, dicho mensaje aparecerá casi instantáneamente después de presionar el inicio de sesión botón). Lo más probable es que esto se debe a que cuando trabaje con el formulario, los procedimientos de evento tienen una prioridad más alta en comparación con el proceso activado. En el caso de la solicitud de consola, todos los procedimientos tienen la misma prioridad. Discutiremos la pregunta de prioridad más adelante, pero por ahora instalaré la mayor prioridad para la persona que llama (principal):

    Hilo.currentthread.priority \u003d _ ThreadPriority.Hight Thread1.Start ()

    Ahora la ventana aparece casi de inmediato. Como puede ver, cree instancias del objeto de hilo de dos maneras. Al principio, usamos el primero de ellos, creó un nuevo objeto (Stream) Thread1 y trabajó con él. La segunda opción es obtener el objeto de subproceso para el flujo realizado actualmente utilizando el método estático detrifa. Por lo tanto, el principal procedimiento en sí ha establecido una prioridad más alta, pero podría hacerlo por cualquier otro flujo, por ejemplo:

    Thread1.Priority \u003d ThreadPriority.Lowest Thread1.Start ()

    Para mostrar cómo administrar el proceso de ejecución, agregue dichas líneas de código al final del procedimiento:

    Ahora ejecute la solicitud al mismo tiempo que realiza algunas operaciones con el mouse (espero que haya elegido el nivel de demora deseado en trabajador, para que el proceso no sea muy rápido, pero no demasiado lento).

    Primero, "Proceso 1" comenzará en la ventana de la consola y el mensaje "Aparecerá la primera corriente". "Proceso 1" se ejecuta, y rápidamente hace clic en Aceptar en la ventana del mensaje.

    Siguiente: "Process 1" continúa, pero en dos segundos aparece un mensaje "Stream está suspendido". Medición de "proceso 1". Haga clic en el botón "Aceptar" en la ventana Mensajes: "Proceso 1" continuó su ejecución y la completó con éxito.

    En este fragmento, utilizamos el método de sueño para suspender el proceso actual. Nota: El sueño es un método estático y solo se puede aplicar al proceso actual, pero no a alguna instancia del objeto de hilo. La sintaxis del idioma le permite escribir THIDE1.SLEEP o THRING.SLEEP, pero aún así, en este caso, use el objeto estipulado.

    El método de sueño también puede usar un argumento 0. En este caso, el flujo actual liberará el residuo cuántico no utilizado asignado para ello.

    Otra opción interesante para usar el sueño, con el valor del tiempo de espera .infinite. En este caso, el flujo se suspenderá por un período indefinido hasta que este estado se vea interrumpido por otra corriente usando el método de hilo.interrupt.

    Para pausar una corriente externa de otra corriente sin detenerse de este último, debe usar el método de hilos. Luego, para continuar su ejecución puede ser el método de rosca.Resume, que hemos hecho en el código anterior.

    Un poco sobre las corrientes de sincronización

    La sincronización de las transmisiones es una de las tareas principales al escribir aplicaciones multi-roscadas, y en el espacio de sistema. Hay un gran conjunto de herramientas para resolverlo. Pero ahora nos familiarizaremos solo con el método de hilo.Join, que le permite aprender el final del flujo. Para ver cómo funciona, reemplace las últimas líneas del procedimiento principal en este código:

    Gestión de prioridades de proceso

    La distribución de la cantidad de tiempo del procesador entre las subprocesos se realiza utilizando prioridades que se especifican como la propiedad de Hilo.Priority. Para las corrientes creadas durante el período de ejecución, puede establecer cinco valores: más alto, abovenormal, normal (utilizado por defecto), Balownormal y más bajo. Para ver cómo las prioridades están influenciadas por la velocidad de transmisión, escriba un código de este tipo para el procedimiento principal:

    SUB PRINCIPAL () "DESCRIPCIÓN DEL PRIMER PROCESO Tema Dim Thread1 como Thread Dim Oworker1 como nuevo WorkerThreadThreadSclass () Thread1 \u003d Nuevo hilo (Dirección de _ Oworker1.WorkerThread)" Thread1.Priority \u003d _ "ThreadPriority.Bebownormal" Transmitimos datos de origen: Oworker1. Inicio \u003d 1 Oworker1.Finish \u003d 10 OWorker1.ThreadName \u003d "Contando 1" Oworker1.symThread \u003d "". "DESCRIPCIÓN DEL SEGUNDO PROCESO Dim Thread2 AS HASTE DIM OWORKER2 AS NUEVO WORDERTHERTHREADSCLASS () THRING2 \u003d Hilo nuevo (Dirección de _ Oworker2.WorkerThread)" Transmitimos datos de origen: OWorker2.start \u003d 11 Oworker2.Finish \u003d 20 Oworker2.threadname \u003d "Cuenta atrás 2 "Oworker2 .symphread \u003d" * "" "Ejecute cualquier hilo.currentthread.priority \u003d _ ThreadPrority.Hight Thread1.Start () Thread2.Start ()" Esperando la finalización de los procesos de Thread1.join (). ) MsgBox ("Ambos procesos terminados") Fin Sub

    Tenga en cuenta que una clase se usa aquí para crear múltiples hilos. Comencemos la solicitud y veamos la dinámica de la ejecución de dos arroyos (Fig. 3). Muestra que en general se realizan a la misma velocidad, el primero está un poco por delante debido al lanzamiento anterior.

    Ahora, antes de comenzar el primer hilo, estableceremos una prioridad para ello por un nivel a continuación:

    Thread1.Priority \u003d _ ThreadPriority.Bebownormal

    La imagen ha cambiado dramáticamente: la segunda transmisión se quitó casi completamente todo el tiempo en la primera (Fig. 4).

    También notamos el uso del método de unión. Con él, realizamos una opción bastante común para sincronizar los flujos, en los que el programa principal está esperando la finalización de varios procesos de computación paralela.

    Conclusión

    Solo afectamos los conceptos básicos del desarrollo de aplicaciones .NET multi-roscadas. Una de las más difíciles y en la práctica de temas tópicos es la sincronización de los flujos. Además de la aplicación del objeto de hilo descrito en este artículo (tiene muchos métodos y propiedades que no hemos considerado aquí), las clases de monitor y mutex se juegan en la gestión del flujo, así como los operadores de bloqueo (C #) y el sinclock (Vb.net).

    Una descripción más detallada de esta tecnología se da en capítulos de libros separados y, de los cuales me gustaría traer algunas citas (con las que estoy totalmente de acuerdo) como un resumen muy breve de la "Multitud de V.Net".

    "Si usted es un principiante, es posible que tenga una sorpresa para encontrar que los costos asociados con la creación y el despacho de flujos pueden llevar al hecho de que la aplicación de un solo roscado funciona más rápido ... Por lo tanto, siempre intente probar los prototipos de ambos prototipos de El programa, un solo roscado y multi-roscado ".

    "Debe abordar cuidadosamente el diseño de MultiShreading y administrar rígidamente el acceso a objetos y variables comunes".

    "No considere la aplicación de MultiShReading como un enfoque predeterminado".

    "Le pregunté a una audiencia que consiste en programadores de VB con experiencia, aunque si obtienen una multitrobidez gratuita de la versión futura de VB. Casi todo levantó las manos. Luego, le pregunté quién sabe lo que va al mismo tiempo. Esta vez las manos levantaban solo un Pocas personas. Y en sus caras estaban comprensivas sonrisas ".

    "Si no comió las dificultades asociadas con el diseño de aplicaciones multi-roscadas, con el uso adecuado de multiprigencia con capacidad para mejorar significativamente el rendimiento de la aplicación".

    Desde mí, agregaré que la tecnología de crear aplicaciones de .NET multi-roscada (como muchas otras tecnologías.net) generalmente es prácticamente independiente del idioma utilizado. Por lo tanto, aconsejo a los desarrolladores que estudien diferentes libros y artículos, independientemente de qué lenguaje de programación se seleccione en ellos para demostrar esta o esa tecnología.

    Literatura:

    1. Dan Epplman. Transición a vb.net: estrategias, conceptos, código / trans. De inglés - SPB.: "Peter", 2002, - 464 P.: Il.
    2. Tom Archer. Conceptos básicos C #. La última tecnología / trans. De inglés - M.: Publicación y comercialización "Edición rusa", 2001. - 448 pág.: Il.

    Multitarea y multithreading

    Comencemos con una afirmación tan simple: los sistemas operativos de Windows de 32 bits son compatibles con los modos de procesamiento de datos de multipropiedad (multiprocesamiento) y multi-roscados. Puede discutir qué tan bien lo hacen, pero esta es otra pregunta.

    La multitarea es un modo de operación cuando la computadora puede realizar varias tareas al mismo tiempo, en paralelo. Está claro que si la computadora tiene un procesador, entonces estamos hablando de pseudo paralelismo cuando el sistema operativo de acuerdo con algunas reglas puede realizar una conmutación rápida entre diferentes tareas. La tarea es un programa o parte del programa (aplicación) que realiza un efecto lógico y es una unidad para la cual el sistema operativo destaca los recursos. Se puede suponer que varias en una forma simplificada se pueden suponer que en Windows, la tarea es cada componente de software implementado como un módulo ejecutable separado (EXE, DLL). Para Windows, el concepto de "tarea" tiene el mismo significado que "proceso", que, en particular, significa ejecutar el código del programa estrictamente en el espacio de direcciones asignado para ello.

    Hay dos tipos principales de multitarea: colaboración (cooperativa) y desplazamiento (preventivo). La primera opción implementada en versiones anteriores de Windows proporciona la conmutación entre tareas solo en el momento de la circulación de una tarea activa a SO (por ejemplo, para E / S). En este caso, cada hilo es responsable de devolver el control del sistema operativo. Si la tarea se olvidó de hacer una operación de este tipo (por ejemplo, mirada), luego a menudo condujo a la cuelga de toda la computadora.

    La multitarea es el modo cuando OS en sí es responsable de emitir una rebanada de tiempo debido a cada flujo (rebanada de tiempo), después de lo cual (si hay solicitudes de otras tareas), interrumpe automáticamente este flujo y decide que para comenzar a comenzar más. Anteriormente, este modo fue llamado - "Con una división del tiempo".

    ¿Cuál es el flujo? El flujo es un proceso de computación autónomo, pero no en el nivel del sistema operativo, sino dentro de la tarea. La diferencia fundamental del flujo desde el "proceso de problema" es que todos los flujos de tarea se realizan en un solo espacio de direcciones, es decir, pueden trabajar con recursos de memoria comunes. Estas son las ventajas de sus ventajas (procesamiento de datos paralelas) y desventajas (amenaza de la fiabilidad del programa). Debe tenerse en cuenta que, en el caso de la multitarea para la protección de las solicitudes, es responsable principalmente para el sistema operativo, y el propio desarrollador es responsable.

    Cabe señalar que el uso del modo multitarea en sistemas de procesador único le permite aumentar la productividad general del sistema multitarea en su conjunto (aunque no siempre, ya que aumenta la proporción de los recursos involucrados en la operación de la OS, aumenta). Pero el momento de la ejecución de una tarea en particular es siempre, al menos no mucho, aumenta debido a la operación adicional del sistema operativo.

    Si el procesador está fuertemente cargado con tareas (con entradas mínimas para la E / S, por ejemplo, en el caso de resolver problemas puramente matemáticos), el aumento general real de la productividad se logra solo cuando se utiliza sistemas multiprocesadores. Dichos sistemas permiten diferentes patrones de paralelización, a nivel de tareas (cada tarea solo puede ocupar un procesador, los flujos son solo pseudo-paralelo) o a nivel de transmisión (cuando una tarea puede ocupar varios procesadores con sus flujos).

    También es posible recordar que cuando opere sistemas de computación potentes para uso colectivo, la fuente de la familia IBM SYSTEM / 360 Familia fue a fines de los años 60, una de las tareas más apremiantes fue la elección de una variante óptima de la administración de la multitarea, incluida En un modo dinámico, teniendo en cuenta varios parámetros. En principio, el control del modo multitarea es la función del sistema operativo. Pero la efectividad de esta o esa opción está directamente relacionada con las características de la arquitectura de la computadora en su conjunto, y especialmente el procesador. Por ejemplo, el mismo sistema IBM de alto rendimiento / 360 trabajó perfectamente en los equipos de uso colectivo en el campo de las tareas comerciales, pero no se adaptó completamente para resolver las tareas de la tarea de clase real. En esta área, luego condujo claramente las mini-computadoras significativamente más baratas y simples como DIG PDP 11/20.

    ¿Qué tema causa más preguntas y dificultades de los principiantes? Cuando pregunté por este maestro y el programador de Java Alexander Prykhin, respondió de inmediato: "MultiPhreading". ¡Gracias por la idea y ayuda en la preparación de este artículo!

    Miraremos en el mundo interior de la solicitud y sus procesos, nos ocuparemos de la esencia de MultiThreading cuando sea útil y cómo implementarlo, en el ejemplo de Java. Si aprendemos otro idioma de la OOP, no se confunda: los principios básicos de los mismos.

    Sobre los arroyos y sus orígenes

    Para entender a MultiPhreading, primero respira lo que es el proceso. El proceso es parte de la memoria virtual y los recursos que destaca el sistema operativo para ejecutar el programa. Si abre varias instancias de una aplicación, cada sistema asignará el proceso. En los navegadores modernos, un proceso separado puede ser responsable de cada pestaña.

    Probablemente se encontró con un "Administrador de tareas de Windows" (en Linux, es un "Monitor del sistema") y sepa que los procesos de ejecución innecesarios cargan el sistema, y \u200b\u200bel más "pesado" de ellos a menudo se cuelga, para que tengan que completar por la fuerza.

    Pero los usuarios les encanta la multitarea: no coma pan: abrímosme con una docena de ventanas y salte allí y aquí. Hay un dilema: debe proporcionar una aplicación simultánea de aplicaciones y, al mismo tiempo, reducir la carga en el sistema para que no se reduzca. Supongamos que la "glándula" no se escabulle con las necesidades de los propietarios, debe decidir sobre el nivel del programa.

    Queremos que el procesador por unidad de tiempo realice más comandos y procese más datos. Es decir, tenemos que encajar en cada cantidad de tiempo más que el código realizado. Imagina un código de ejecución en forma de un objeto: este es el flujo.

    Es más fácil acercarse a un asunto difícil si lo dividiste en algunos simples. Entonces, cuando trabaje con memoria: el proceso "pesado" se divide en arroyos que ocupan menos recursos y, en lugar de llegar al código antes de la computadora (tan precisamente, ver más abajo).

    Cada aplicación tiene al menos un proceso, y cada proceso tiene un mínimo de una corriente, que se llama la principal y, si es necesario, lanza otras nuevas.

    La diferencia entre las corrientes y los procesos.

      Los arroyos utilizan la memoria asignada en el proceso, y los procesos requieren un lugar separado en la memoria. Por lo tanto, los flujos se crean y se completan más rápido: el sistema no necesita asignar el nuevo espacio de direcciones cada vez, y luego liberarlo.

      Cada proceso funciona con sus datos, para intercambiar algo que solo pueden a través del mecanismo de interacción de interprocesamiento. Los hilos se convierten en datos y recursos entre sí directamente: que cambiaron uno, inmediatamente accesible para todos. El flujo puede controlar al "compañero" en el proceso, mientras que el proceso controla exclusivamente sus "hijas". Por lo tanto, cambiar entre las corrientes más rápido y la comunicación entre ellos se organiza simplemente.

    ¿Cuál es la conclusión de aquí? Si necesita manejar una gran cantidad de datos lo más rápido posible, dispersemos en piezas que pueden procesarse por flujos individuales y luego recolectan el resultado juntos. Es mejor que producir procesos codiciosos a los recursos.

    Pero, ¿por qué es una aplicación tan popular, ya que Firefox va a crear múltiples procesos? Debido a que es para el navegador que el funcionamiento aislado de las pestañas es de manera confiable y flexible. Si algo está mal con un proceso, no es necesario completar todo el programa: es posible guardar al menos parte de los datos.

    Que es multithreading

    Así que llegamos a lo principal. El hilo múltiple es cuando el proceso de la aplicación se divide en flujos paralelos a una unidad de tiempo, procesada por un procesador.

    La carga de computación se distribuye entre dos o más núcleos, de modo que la interfaz y otros componentes del programa no se desaceleran entre sí.

    Las aplicaciones multi-roscadas se pueden iniciar en procesadores de un solo núcleo, pero luego los flujos se realizan a su vez: se trabajó por primera vez, se guardó su condición: se les administró para trabajar el segundo, regresaron, regresó a la primera o comenzó el tercero, etc.

    Las personas ocupadas se quejan de que solo tienen dos manos. Los procesos y programas pueden tener tantas manos según sea necesario para la tarea rápida.

    Espere la señal: Sincronización en aplicaciones multi-roscadas

    Imagine que varios arroyos están tratando de cambiar simultáneamente el mismo área de datos. ¿Cuyos cambios se aceptarán eventualmente, y cuyas se cancelan? Para que el trabajo con recursos comunes no conduzca a la confusión, las hilos deben coordinar sus acciones. Para hacer esto, intercambian información usando señales. Cada corriente informa a otros lo que está haciendo ahora y qué cambios para esperar. Por lo tanto, los datos de todas las corrientes sobre el estado actual de los recursos se sincronizan.

    Medios básicos de sincronización

    Exclusión mutuamente (Exclusión mutua, abreviada - mutex) - "Casilla de verificación", pasando al flujo, que en este momento tiene derecho a trabajar con los recursos compartidos. Elimina el acceso de otras corrientes al área ocupada de la memoria. Los mutexes en el apéndice pueden ser varios, y pueden separarse entre los procesos. Hay captura: MUTEX hace que la solicitud sea cada vez que acceda al núcleo del sistema operativo, que se asigna.

    Semáforo - Le permite limitar la cantidad de flujos que tienen acceso al recurso en un punto en particular. Por lo tanto, reducirá la carga en el procesador cuando se ejecute el código, donde hay cuellos de botella. El problema es que el número óptimo de flujos depende de la máquina del usuario.

    Evento - Defina una condición cuando se pasa el control al flujo deseado. Los flujos de datos del evento intercambian para desarrollar y continuar lógicamente las acciones de cada uno. Uno recibió datos, el otro revisó su corrección, el tercero - retenido en el disco duro. Los eventos difieren en el método de cancelar la señal sobre ellos. Si necesita notificar algunos flujos sobre el evento, debe configurar manualmente la función de cancelación para detener la señal. Si el flujo de destino es solo uno, puede crear un evento con reinicio automático. Parará la señal misma, después de que se trata de la corriente. Para la gestión de flujo de eventos flexible, puede alinearse.

    Sección crítica - Un mecanismo más complejo que combina el medidor de ciclo y el semáforo. El medidor le permite posponer el lanzamiento del semáforo en el momento adecuado. La ventaja es que el kernel está involucrado solo si la sección está ocupada y necesita incluir a Semaphore. El resto del tiempo el hilo se realiza en modo de usuario. Ay, la sección solo se puede utilizar dentro de un solo proceso.

    Cómo implementar multithreading en Java

    Para trabajar con flujos en Java, la clase de hilo es responsable. Cree un nuevo hilo para ejecutar la tarea: significa crear una instancia de la clase de subproceso y vincularla con el código deseado. Puede hacer esto de dos maneras:

      forma de subclase de hilo;

      implementando en su interfaz de clasificación de clase, después de lo cual es posible transmitir instancias de clase en el constructor de hilo.

    Si bien no afectaremos el tema de los puntos muertos (puntos muertos), cuando los arroyos bloquean el trabajo entre sí y cuelgan, lo dejan para el siguiente artículo. Y ahora vamos a practicar.

    Un ejemplo de multithreading en Java: Ping Pong Mutexes

    Si crees que ahora habrá algo terrible, exhale. Trabajar con objetos de sincronización Miraremos casi un formulario de juego: Dos hilos se transferirán a Mutex "Ohm. Pero en esencia, verá una aplicación real, donde, al mismo tiempo, solo un hilo puede procesar los datos disponibles públicamente.

    Primero cree una clase, heredando las propiedades del hilo ya conocido por nosotros, y escriba el método "Kickball" (Kickball):

    La clase pública PingpongThread extiende el hilo (pingpongthread (nombre de cadena); // anula el nombre del flujo) @override Public Void Run () (bola de bola \u003d ball.getball (); while (ball.ingingame ()) (kickball (ball); )) Playa void privada (bola de bola) (si (si (! Ball.getside (). Es igual (getName ())) (Ball.kick (GetName ())))))))

    Ahora cuida la pelota. No será simple con nosotros, sino un memorable: así como pudo decir, quien lo golpeó, de qué lado y cuántas veces. Para hacer esto, use MUTEX: recopilará información sobre el funcionamiento de cada uno de los flujos, esto permitirá que las corrientes aisladas se comuniquen entre sí. Después del 15º golpe, traen la pelota del juego, de modo que no se lesiona con fuerza.

    Bola de clase pública (patadas privadas \u003d 0; instancia de la bola estática privada \u003d bola nueva (); lado de la cuerda privada \u003d ""; bola privada () () Ball Ball GetBall () (instancia de retorno;) Patada de voides sincronizada (nombre de juego de cadena) (Kicks ++; Side \u003d Playername; System.out.Println (Kicks + "" + Lado);) String Getside () (Lado de regreso;) Boolean Isingame () (Volver< 15); } }

    Y ahora la escena da a la jugadora. Llamemos, no los cáusticos, Ping y Pong:

    Clase pública PingpongGame (PingpongThread Player1 \u003d New PingpongThread ("Ping"); PingpongThread Player2 \u003d nuevo PingpongThread ("Pong"); Bola de bola; PingpongGame () (Ball \u003d ball.getball ();) Void StartGame () Lanza InterruptException (Player11 .start (); jugador2.start ();))

    "Estadio completo de la gente: tiempo para comenzar el partido". Declararemos la apertura de la reunión oficialmente, en la clase principal de la solicitud:

    Clase pública Pingpong (indicando públicos que indican el vacío principal (cadena args) lanza interrumpidaException (pingponggame game \u003d new pingponggame (); juego.startgame ();))

    Como puedes ver, no hay nada deuotrotrial. Es solo una introducción a MultiShreading, pero ya imaginas cómo funciona, y puedes experimentar, limitar la duración del juego, no por el número de choques, sino por el tiempo, por ejemplo. Volveremos al tema de MultiPhreading: considere el paquete java.util.concurrent, la biblioteca Akka y el mecanismo de voltio. Y todavía hablamos de la implementación de MultiThreading en Python.

    Breses de arcilla

    Introducción

    Los métodos para la implementación de MultiThreading utilizados por los especialistas de Intel incluyen cuatro etapas principales: análisis, desarrollo e implementación, depuración y configuración del rendimiento. Este enfoque se utiliza para crear una aplicación multithreadizada de un código de programa en serie. Trabajar con software en el curso de la primera, tercera y cuarta etapas se destaca de manera bastante amplia, mientras que la información sobre la implementación del segundo paso claramente no es suficiente.

    Se llevaron a cabo muchos libros dedicados a algoritmos paralelos y computación paralela. Sin embargo, en estas publicaciones, la transferencia de mensajes, sistemas con memoria distribuida o patrones paralelos teóricos de cálculos, a veces no aplicables a plataformas de múltiples núcleos reales. Si está listo para participar seriamente en la programación multi-roscada, probablemente necesitará conocimiento sobre el desarrollo de algoritmos para estos modelos. Por supuesto, el uso de estos modelos es lo suficientemente limitado, tantos desarrolladores de software pueden tener que ser implementados en la práctica.

    {!LANG-3a65cae9a17db9c1ae2aac7a164999d5!}

    {!LANG-c802333555947711ae6802866de008d5!}

    {!LANG-41e56658022a7d53da47e1c07e797825!}

    {!LANG-655327c11e9ea015a8c598dc83a489fa!}

    {!LANG-50583fa4c5ec845dc930eded5832b48b!}

    {!LANG-090008de069428954137a08df72830e1!}

    {!LANG-c6513b3ca28fa4c6d21c6072d32fe0d7!}

    {!LANG-7a44c11a63d280a0883889f7e6c27970!}

    {!LANG-49f7ed5eea728bc092b840d5dc741aee!}

    {!LANG-146d3fd353bfaafc10ab6c9edbc3fe98!}

    {!LANG-0b1db0ecc7be8367491562ac93da9316!}

    {!LANG-7407ee55ab98fdb20d1e046387909272!}

    {!LANG-90707825c79241d3f45ca8d13823c1bc!}

    {!LANG-cb83ead86a02ca7f9631bcefaff6ff35!}

    {!LANG-b814285480f9d0c81b6401633aea6e91!}

    {!LANG-7fa498f5c44482181932f1bd925a605a!}

    {!LANG-e8ecebd7e44a1091930a8a32428829a5!}

    {!LANG-81d6e934c5d6c8c8d106d21a46471c47!}

    {!LANG-8ceaacbadc9b0655853f9b3a32076d50!}

    {!LANG-e0c7c945c74c7bb80a80a40e0a21ea32!}

    {!LANG-3308dfc2ba1566391fc7f18a9b9fc113!}

    {!LANG-f1778a6b639832a6b1b94175bb497d7a!}

    {!LANG-5885f7b09dcc49e0ea4b0913f34fc670!}

    {!LANG-5793786da9e8a8cf350b6f181a8a570b!}

    {!LANG-43ff1a9cf72bb5274d9dec899dd9f4be!}

    {!LANG-74ce96fbb1a6b21a07a7c5d803ad11e9!}

    {!LANG-fb507189ca12c5e9d84cf21fc6aeb3ff!}

    {!LANG-b96af12fac6d7bb85b09908b9575fe24!}

    {!LANG-fbb6c42c7acb76bd0b95e490593f0e67!}

    {!LANG-e69bb9227b9418eae1fb142ec4b01967!}

    {!LANG-30384b5d2cd21bee6a7b4232b78dc99f!}

    {!LANG-79a72f824ee4e9e7b1fc287056acce74!}

    {!LANG-fd34069074ea85e3ce742995898aa810!}

    {!LANG-881c73fc63fd9425312ad995a2dffeaf!}

    {!LANG-d9646c3855fa6f56d153367a277c87ec!}

    {!LANG-4111238ae824b51d642f7f415a426bcc!}

    {!LANG-93ce797abeced2487223c78ca89c6683!}

    {!LANG-52d23c2b867c5bc41b09dc87968b3ed3!}

    {!LANG-480d9a9eedfda6502489a912f2fdd3c2!}

    {!LANG-b6913147b1d17d126fd45b93a1725c61!}