C #: subprocesos múltiples

UN threadse define como la ruta de ejecución de un programa. Cada hilo define un flujo de control único. Si su aplicación implica operaciones complicadas y que requieren mucho tiempo, a menudo es útil establecer diferentes rutas de ejecución o subprocesos, con cada subproceso realizando un trabajo en particular.

Los hilos son lightweight processes. Un ejemplo común de uso de hilo es la implementación de programación concurrente por sistemas operativos modernos. El uso de subprocesos evita el desperdicio del ciclo de la CPU y aumenta la eficiencia de una aplicación.

Hasta ahora escribimos los programas donde un solo hilo se ejecuta como un solo proceso que es la instancia en ejecución de la aplicación. Sin embargo, de esta forma la aplicación puede realizar un trabajo a la vez. Para que ejecute más de una tarea a la vez, se podría dividir en subprocesos más pequeños.

Ciclo de vida del hilo

El ciclo de vida de un hilo comienza cuando se crea un objeto de la clase System.Threading.Thread y finaliza cuando el hilo termina o completa su ejecución.

A continuación se muestran los distintos estados del ciclo de vida de un hilo:

  • The Unstarted State - Es la situación en la que se crea la instancia del hilo pero no se llama al método Start.

  • The Ready State - Es la situación en la que el hilo está listo para ejecutarse y espera el ciclo de la CPU.

  • The Not Runnable State - Un hilo no es ejecutable, cuando

    • Se ha llamado al método de sueño
    • Se ha llamado al método de espera
    • Bloqueado por operaciones de E / S
  • The Dead State - Es la situación en la que el hilo completa la ejecución o se aborta.

El hilo principal

En C #, el System.Threading.ThreadLa clase se usa para trabajar con subprocesos. Permite crear y acceder a subprocesos individuales en una aplicación multiproceso. El primer hilo que se ejecutará en un proceso se llamamain hilo.

Cuando un programa C # comienza a ejecutarse, el hilo principal se crea automáticamente. Los hilos creados con elThreadclass se denominan subprocesos secundarios del subproceso principal. Puede acceder a un hilo usando elCurrentThread propiedad de la clase Thread.

El siguiente programa demuestra la ejecución del hilo principal:

using System;
using System.Threading;

namespace MultithreadingApplication {
   class MainThreadProgram {
      static void Main(string[] args) {
         Thread th = Thread.CurrentThread;
         th.Name = "MainThread";
         
         Console.WriteLine("This is {0}", th.Name);
         Console.ReadKey();
      }
   }
}

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

This is MainThread

Propiedades y métodos de la clase Thread

La siguiente tabla muestra algunos de los más utilizados properties del Thread clase -

No Señor. Descripción de propiedad
1

CurrentContext

Obtiene el contexto actual en el que se ejecuta el subproceso.

2

CurrentCulture

Obtiene o establece la referencia cultural del subproceso actual.

3

CurrentPrinciple

Obtiene o establece el principal actual del subproceso (para seguridad basada en roles).

4

CurrentThread

Obtiene el subproceso que se está ejecutando actualmente.

5

CurrentUICulture

Obtiene o establece la cultura actual que utiliza Resource Manager para buscar recursos específicos de la cultura en tiempo de ejecución.

6

ExecutionContext

Obtiene un objeto ExecutionContext que contiene información sobre los distintos contextos del subproceso actual.

7

IsAlive

Obtiene un valor que indica el estado de ejecución del subproceso actual.

8

IsBackground

Obtiene o establece un valor que indica si un subproceso es o no un subproceso en segundo plano.

9

IsThreadPoolThread

Obtiene un valor que indica si un subproceso pertenece o no al grupo de subprocesos administrado.

10

ManagedThreadId

Obtiene un identificador único para el subproceso administrado actual.

11

Name

Obtiene o establece el nombre del hilo.

12

Priority

Obtiene o establece un valor que indica la prioridad de programación de un hilo.

13

ThreadState

Obtiene un valor que contiene los estados del subproceso actual.

La siguiente tabla muestra algunos de los más utilizados methods del Thread clase -

No Señor. Método y descripción
1

public void Abort()

Genera una ThreadAbortException en el hilo en el que se invoca, para comenzar el proceso de terminación del hilo. Llamar a este método generalmente termina el hilo.

2

public static LocalDataStoreSlot AllocateDataSlot()

Asigna una ranura de datos sin nombre en todos los subprocesos. Para un mejor rendimiento, utilice campos que estén marcados con el atributo ThreadStaticAttribute en su lugar.

3

public static LocalDataStoreSlot AllocateNamedDataSlot(string name)

Asigna una ranura de datos con nombre en todos los subprocesos. Para un mejor rendimiento, utilice campos que estén marcados con el atributo ThreadStaticAttribute en su lugar.

4

public static void BeginCriticalRegion()

Notifica a un host que la ejecución está a punto de ingresar en una región de código en la que los efectos de un aborto de un hilo o una excepción no controlada pueden poner en peligro otras tareas en el dominio de la aplicación.

5

public static void BeginThreadAffinity()

Notifica a un host que el código administrado está a punto de ejecutar instrucciones que dependen de la identidad del subproceso del sistema operativo físico actual.

6

public static void EndCriticalRegion()

Notifica a un host que la ejecución está a punto de ingresar a una región de código en la que los efectos de un aborto de hilo o una excepción no controlada se limitan a la tarea actual.

7

public static void EndThreadAffinity()

Notifica a un host que el código administrado ha terminado de ejecutar instrucciones que dependen de la identidad del subproceso del sistema operativo físico actual.

8

public static void FreeNamedDataSlot(string name)

Elimina la asociación entre un nombre y una ranura, para todos los hilos del proceso. Para un mejor rendimiento, utilice campos que estén marcados con el atributo ThreadStaticAttribute en su lugar.

9

public static Object GetData(LocalDataStoreSlot slot)

Recupera el valor de la ranura especificada en el hilo actual, dentro del dominio actual del hilo actual. Para un mejor rendimiento, utilice campos que estén marcados con el atributo ThreadStaticAttribute en su lugar.

10

public static AppDomain GetDomain()

Devuelve el dominio actual en el que se está ejecutando el hilo actual.

11

public static AppDomain GetDomainID()

Devuelve un identificador de dominio de aplicación único

12

public static LocalDataStoreSlot GetNamedDataSlot(string name)

Busca una ranura de datos con nombre. Para un mejor rendimiento, utilice campos que estén marcados con el atributo ThreadStaticAttribute en su lugar.

13

public void Interrupt()

Interrumpe un subproceso que está en el estado de subproceso WaitSleepJoin.

14

public void Join()

Bloquea el subproceso de llamada hasta que termina un subproceso, mientras continúa realizando el bombeo estándar COM y SendMessage. Este método tiene diferentes formularios sobrecargados.

15

public static void MemoryBarrier()

Sincroniza el acceso a la memoria de la siguiente manera: El procesador que ejecuta el subproceso actual no puede reordenar las instrucciones de tal manera que los accesos a la memoria antes de la llamada a MemoryBarrier se ejecutan después de los accesos a la memoria que siguen a la llamada a MemoryBarrier.

dieciséis

public static void ResetAbort()

Cancela un aborto solicitado para el hilo actual.

17

public static void SetData(LocalDataStoreSlot slot, Object data)

Establece los datos en la ranura especificada en el subproceso actualmente en ejecución, para el dominio actual de ese subproceso. Para un mejor rendimiento, use campos marcados con el atributo ThreadStaticAttribute en su lugar.

18

public void Start()

Inicia un hilo.

19

public static void Sleep(int millisecondsTimeout)

Hace que el hilo se detenga por un período de tiempo.

20

public static void SpinWait(int iterations)

Hace que un hilo espere el número de veces definido por el parámetro de iteraciones

21

public static byte VolatileRead(ref byte address)

public static double VolatileRead(ref double address)

public static int VolatileRead(ref int address)

public static Object VolatileRead(ref Object address)

Lee el valor de un campo. El valor es el último escrito por cualquier procesador en una computadora, sin importar la cantidad de procesadores o el estado de la caché del procesador. Este método tiene diferentes formularios sobrecargados. Solo algunos se dan arriba.

22

public static void VolatileWrite(ref byte address,byte value)

public static void VolatileWrite(ref double address, double value)

public static void VolatileWrite(ref int address, int value)

public static void VolatileWrite(ref Object address, Object value)

Escribe un valor en un campo inmediatamente, de modo que el valor sea visible para todos los procesadores de la computadora. Este método tiene diferentes formularios sobrecargados. Solo algunos se dan arriba.

23

public static bool Yield()

Hace que el subproceso de llamada ceda la ejecución a otro subproceso que está listo para ejecutarse en el procesador actual. El sistema operativo selecciona el hilo al que ceder.

Crear hilos

Los hilos se crean ampliando la clase Thread. La clase Thread extendida luego llama alStart() método para comenzar la ejecución del hilo secundario.

El siguiente programa demuestra el concepto:

using System;
using System.Threading;

namespace MultithreadingApplication {
   class ThreadCreationProgram {
      public static void CallToChildThread() {
         Console.WriteLine("Child thread starts");
      }
      static void Main(string[] args) {
         ThreadStart childref = new ThreadStart(CallToChildThread);
         Console.WriteLine("In Main: Creating the Child thread");
         Thread childThread = new Thread(childref);
         childThread.Start();
         Console.ReadKey();
      }
   }
}

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

In Main: Creating the Child thread
Child thread starts

Gestionar hilos

La clase Thread proporciona varios métodos para administrar subprocesos.

El siguiente ejemplo demuestra el uso de la sleep() método para hacer una pausa en un hilo durante un período de tiempo específico.

using System;
using System.Threading;

namespace MultithreadingApplication {
   class ThreadCreationProgram {
      public static void CallToChildThread() {
         Console.WriteLine("Child thread starts");
         
         // the thread is paused for 5000 milliseconds
         int sleepfor = 5000; 
         
         Console.WriteLine("Child Thread Paused for {0} seconds", sleepfor / 1000);
         Thread.Sleep(sleepfor);
         Console.WriteLine("Child thread resumes");
      }
      
      static void Main(string[] args) {
         ThreadStart childref = new ThreadStart(CallToChildThread);
         Console.WriteLine("In Main: Creating the Child thread");
         
         Thread childThread = new Thread(childref);
         childThread.Start();
         Console.ReadKey();
      }
   }
}

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

In Main: Creating the Child thread
Child thread starts
Child Thread Paused for 5 seconds
Child thread resumes

Destruyendo hilos

los Abort() El método se utiliza para destruir hilos.

El tiempo de ejecución aborta el hilo lanzando un ThreadAbortException. Esta excepción no se puede capturar, el control se envía al bloque finalmente , si lo hay.

El siguiente programa ilustra esto:

using System;
using System.Threading;

namespace MultithreadingApplication {
   class ThreadCreationProgram {
      public static void CallToChildThread() {
         try {
            Console.WriteLine("Child thread starts");
            
            // do some work, like counting to 10
            for (int counter = 0; counter <= 10; counter++) {
               Thread.Sleep(500);
               Console.WriteLine(counter);
            }
            
            Console.WriteLine("Child Thread Completed");
         } catch (ThreadAbortException e) {
            Console.WriteLine("Thread Abort Exception");
         } finally {
            Console.WriteLine("Couldn't catch the Thread Exception");
         }
      }
      static void Main(string[] args) {
         ThreadStart childref = new ThreadStart(CallToChildThread);
         Console.WriteLine("In Main: Creating the Child thread");
         
         Thread childThread = new Thread(childref);
         childThread.Start();
         
         //stop the main thread for some time
         Thread.Sleep(2000);
         
         //now abort the child
         Console.WriteLine("In Main: Aborting the Child thread");
         
         childThread.Abort();
         Console.ReadKey();
      }
   }
}

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

In Main: Creating the Child thread
Child thread starts
0
1
2
In Main: Aborting the Child thread
Thread Abort Exception
Couldn't catch the Thread Exception