Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
[Tutorial] C# subprocesamiento [Xtrem]
#1


Tutorial de subprocesamiento
Visual Studio .NET 2003
La ventaja principal del subprocesamiento es la capacidad de crear aplicaciones que usan más de un subproceso de ejecución. Por ejemplo, un proceso puede tener un subproceso de interfaz de usuario que administre la interacción con el usuario, y otros subprocesos de trabajo que realicen otras tareas mientras el subproceso de interfaz de usuario espera a que el usuario proporcione datos.

Este tutorial muestra varias actividades con subprocesos:

Crear y ejecutar un subproceso
Sincronización de subprocesos
Interacción entre subprocesos
Utilizar un grupo de subprocesos
Utilizar una exclusión mutua para proteger un recurso compartido
Archivos de ejemplo

Vea Ejemplo de subprocesamiento para descargar y generar los archivos de ejemplo que se utilizan en este tutorial.

Información adicional

Subprocesos y subprocesamiento
Objetos y características de subprocesamiento
System.Threading (Espacio de nombres)
Instrucción lock
Ejemplo de la tecnología de sincronización de sistemas de espera
Tutorial

Este tutorial contiene los siguientes temas:

Ejemplo 1: crear, iniciar e interactuar con subprocesos
Ejemplo 2: sincronizar dos subprocesos: productor y consumidor
Ejemplo 3: utilizar un grupo de subprocesos
Ejemplo 4: utilizar el objeto de exclusión mutua
Ejemplo 1: crear, iniciar e interactuar con subprocesos

Este ejemplo muestra cómo crear e iniciar un subproceso, y presenta la interacción entre dos subprocesos que se ejecutan simultáneamente dentro del mismo proceso. Observe que no es necesario detener ni liberar el subproceso. De ello se encarga automáticamente Common Language Runtime de .NET Framework.

El programa comienza creando un objeto de tipo Alpha (oAlpha) y un subproceso (oThread) que hace referencia al método Beta de la clase Alpha. A continuación se inicia el subproceso. La propiedad IsAlive del subproceso permite al programa esperar hasta que se inicialice el subproceso (se cree, se asigne, etc.) Se obtiene acceso al subproceso principal a través de Thread, y el método Sleep indica al subproceso que libere su franja de tiempo asignada y detenga la ejecución durante un determinado tiempo de milisegundos. El subproceso oThread se detiene a continuación y se realiza una operación "Join" en él. Realizar "Join" en un subproceso hace que el subproceso principal espere a que finalice éste o espere un tiempo especificado a que expire (para más detalles, vea Thread.Join (Método)). Por último, el programa intenta reiniciar oThread, pero no lo consigue porque no se puede reiniciar un subproceso hasta después de detenerse. Para obtener información sobre el cese temporal de la ejecución, vea Suspender la ejecución de subprocesos.

Código PHP:
// StopJoin.cs
using System;
using System.Threading;

public class 
Alpha
{

   
// This method that will be called when the thread is started
   
public void Beta()
   {
      while (
true)
      {
         
Console.WriteLine("Alpha.Beta is running in its own thread.");
      }
   }
};

public class 
Simple
{
   public static 
int Main()
   {
      
Console.WriteLine("Thread Start/Stop/Join Sample");
      
      
Alpha oAlpha = new Alpha();

      
// Create the thread object, passing in the Alpha.Beta method
      // via a ThreadStart delegate. This does not start the thread.
      
Thread oThread = new Thread(new ThreadStart(oAlpha.Beta));

      
// Start the thread
      
oThread.Start();

      
// Spin for a while waiting for the started thread to become
      // alive:
      
while (!oThread.IsAlive);
      
      
// Put the Main thread to sleep for 1 millisecond to allow oThread
      // to do some work:
      
Thread.Sleep(1);
      
      
// Request that oThread be stopped
      
oThread.Abort();
      
      
// Wait until oThread finishes. Join also has overloads
      // that take a millisecond interval or a TimeSpan object.
      
oThread.Join();
      
      
Console.WriteLine();
      
Console.WriteLine("Alpha.Beta has finished");
      
      try 
      {
         
Console.WriteLine("Try to restart the Alpha.Beta thread");
         
oThread.Start();
      }
      catch (
ThreadStateException
      {
         
Console.Write("ThreadStateException trying to restart Alpha.Beta. ");
         
Console.WriteLine("Expected since aborted threads cannot be restarted.");
      }
      return 
0;
   }
}
Resultados del ejemplo

Thread Start
/Stop/Join Sample
Alpha
.Beta is running in its own thread.
Alpha.Beta is running in its own thread.
Alpha.Beta is running in its own thread.
...
...
Alpha.Beta has finished
Try to restart the Alpha.Beta thread
ThreadStateException trying to restart Alpha
.BetaExpected since aborted threads cannot be restarted
Ejemplo 2: sincronizar dos subprocesos: productor y consumidor

El ejemplo siguiente muestra cómo realizar una sincronización a través de la palabra clave de C# lock y el método Pulse del objeto Monitor. El método Pulse notifica un cambio en el estado del objeto a un subproceso situado en la cola de espera (para obtener más información sobre este método, vea Monitor.Pulse (Método)).

El ejemplo crea un objeto Cell con dos métodos: ReadFromCell y WriteToCell. Otros dos objetos se crean a partir de las clases CellProd y CellCons; ambos objetos tienen un método ThreadRun cuya labor consiste en llamar a ReadFromCell y WriteToCell. La sincronización se lleva a cabo esperando la recepción de "pulsos" por parte del objeto Monitor, que llegan por orden. Es decir, en primer lugar se produce un elemento (el consumidor, en ese momento, espera un pulso), después se genera un pulso y a continuación el consumidor consume lo producido (mientras el productor espera un pulso), etc.

Código PHP:
// MonitorSample.cs
// This example shows use of the following methods of the C# lock keyword
// and the Monitor class 
// in threads:
//      Monitor.Pulse(Object)
//      Monitor.Wait(Object)
using System;
using System.Threading;

public class 
MonitorSample
{
   public static 
void Main(String[] args)
   {
      
int result 0;   // Result initialized to say there is no error
      
Cell cell = new Cell( );

      
CellProd prod = new CellProd(cell20);  // Use cell for storage, 
                                               // produce 20 items
      
CellCons cons = new CellCons(cell20);  // Use cell for storage, 
                                               // consume 20 items

      
Thread producer = new Thread(new ThreadStart(prod.ThreadRun));
      
Thread consumer = new Thread(new ThreadStart(cons.ThreadRun));
      
// Threads producer and consumer have been created, 
      // but not started at this point.

      
try
      {
         
producer.Start( );
         
consumer.Start( );

         
producer.Join( );   // Join both threads with no timeout
                             // Run both until done.
         
consumer.Join( );  
      
// threads producer and consumer have finished at this point.
      
}
      catch (
ThreadStateException e)
      {
         
Console.WriteLine(e);  // Display text of exception
         
result 1;            // Result says there was an error
      
}
      catch (
ThreadInterruptedException e)
      {
         
Console.WriteLine(e);  // This exception means that the thread
                                // was interrupted during a Wait
         
result 1;            // Result says there was an error
      
}
      
// Even though Main returns void, this provides a return code to 
      // the parent process.
      
Environment.ExitCode result;
   }
}

public class 
CellProd
{
   
Cell cell;         // Field to hold cell object to be used
   
int quantity 1;  // Field for how many items to produce in cell

   
public CellProd(Cell boxint request)
   {
      
cell box;          // Pass in what cell object to be used
      
quantity request;  // Pass in how many items to produce in cell
   
}
   public 
void ThreadRun( )
   {
      for(
int looper=1looper<=quantitylooper++)
         
cell.WriteToCell(looper);  // "producing"
   
}
}

public class 
CellCons
{
   
Cell cell;         // Field to hold cell object to be used
   
int quantity 1;  // Field for how many items to consume from cell

   
public CellCons(Cell boxint request)
   {
      
cell box;          // Pass in what cell object to be used
      
quantity request;  // Pass in how many items to consume from cell
   
}
   public 
void ThreadRun( )
   {
      
int valReturned;
      for(
int looper=1looper<=quantitylooper++)
      
// Consume the result by placing it in valReturned.
         
valReturned=cell.ReadFromCell( );
   }
}

public class 
Cell
{
   
int cellContents;         // Cell contents
   
bool readerFlag false;  // State flag
   
public int ReadFromCell( )
   {
      
lock(this)   // Enter synchronization block
      
{
         if (!
readerFlag)
         {            
// Wait until Cell.WriteToCell is done producing
            
try
            {
               
// Waits for the Monitor.Pulse in WriteToCell
               
Monitor.Wait(this);
            }
            catch (
SynchronizationLockException e)
            {
               
Console.WriteLine(e);
            }
            catch (
ThreadInterruptedException e)
            {
               
Console.WriteLine(e);
            }
         }
         
Console.WriteLine("Consume: {0}",cellContents);
         
readerFlag false;    // Reset the state flag to say consuming
                                // is done.
         
Monitor.Pulse(this);   // Pulse tells Cell.WriteToCell that
                                // Cell.ReadFromCell is done.
      
}   // Exit synchronization block
      
return cellContents;
   }
   
   public 
void WriteToCell(int n)
   {
      
lock(this)  // Enter synchronization block
      
{
         if (
readerFlag)
         {      
// Wait until Cell.ReadFromCell is done consuming.
            
try
            {
               
Monitor.Wait(this);   // Wait for the Monitor.Pulse in
                                     // ReadFromCell
            
}
            catch (
SynchronizationLockException e)
            {
               
Console.WriteLine(e);
            }
            catch (
ThreadInterruptedException e)
            {
               
Console.WriteLine(e);
            }
         }
         
cellContents n;
         
Console.WriteLine("Produce: {0}",cellContents);
         
readerFlag true;    // Reset the state flag to say producing
                               // is done
         
Monitor.Pulse(this);  // Pulse tells Cell.ReadFromCell that 
                               // Cell.WriteToCell is done.
      
}   // Exit synchronization block
   
}

Resultados del ejemplo

Produce: 1
Consume: 1
Produce: 2
Consume: 2
Produce: 3
Consume: 3
...
...
Produce: 20
Consume: 20
Ejemplo 3: utilizar un grupo de subprocesos

El ejemplo siguiente muestra cómo se utiliza un grupo de subprocesos. En primer lugar crea un objeto ManualResetEvent, que permite al programa conocer el momento en que el grupo de subprocesos finaliza la ejecución de todos los elementos de trabajo. A continuación, intenta agregar un subproceso al grupo de subprocesos. Si tiene éxito, agrega el resto (cuatro en este ejemplo). El grupo de subprocesos colocará entonces los elementos de trabajo en los subprocesos disponibles. Se llama al método WaitOne en eventX, lo que hace que el resto del programa espere hasta la activación del evento (con el método eventX.Set). Por último, el programa imprime la carga (el subproceso que ejecuta en realidad un elemento de trabajo particular) en los subprocesos.

Código PHP:
// SimplePool.cs
// Simple thread pool example
using System;
using System.Collections;
using System.Threading;

// Useful way to store info that can be passed as a state on a work item
public class SomeState
{
   public 
int Cookie;
   public 
SomeState(int iCookie)
   {
      
Cookie iCookie;
   }
}

public class 
Alpha
{
   public 
Hashtable HashCount;
   public 
ManualResetEvent eventX;
   public static 
int iCount 0;
   public static 
int iMaxCount 0;
   public 
Alpha(int MaxCount
   {
      
HashCount = new Hashtable(MaxCount);
      
iMaxCount MaxCount;
   }

   
// Beta is the method that will be called when the work item is
   // serviced on the thread pool.
   // That means this method will be called when the thread pool has
   // an available thread for the work item.
   
public void Beta(Object state)
   {
      
// Write out the hashcode and cookie for the current thread
      
Console.WriteLine(" {0} {1} :"Thread.CurrentThread.GetHashCode(),
         ((
SomeState)state).Cookie);
      
// The lock keyword allows thread-safe modification
      // of variables accessible across multiple threads.
      
Console.WriteLine(
         
"HashCount.Count=={0}, Thread.CurrentThread.GetHashCode()=={1}",
         
HashCount.Count
         
Thread.CurrentThread.GetHashCode());
      
lock (HashCount
      {
         if (!
HashCount.ContainsKey(Thread.CurrentThread.GetHashCode()))
            
HashCount.Add (Thread.CurrentThread.GetHashCode(), 0);
         
HashCount[Thread.CurrentThread.GetHashCode()] = 
            ((int)
HashCount[Thread.CurrentThread.GetHashCode()])+1;
      }

      
// Do some busy work.
      // Note: Depending on the speed of your machine, if you 
      // increase this number, the dispersement of the thread
      // loads should be wider.
      
int iX  2000;
      
Thread.Sleep(iX);
      
// The Interlocked.Increment method allows thread-safe modification
      // of variables accessible across multiple threads.
      
Interlocked.Increment(ref iCount);
      if (
iCount == iMaxCount)
      {
         
Console.WriteLine();
         
Console.WriteLine("Setting eventX ");
         
eventX.Set();
      }
   }
}

public class 
SimplePool
{
   public static 
int Main(string[] args)
   {
      
Console.WriteLine("Thread Pool Sample:");
      
bool W2K false;
      
int MaxCount 10;  // Allow a total of 10 threads in the pool
      // Mark the event as unsignaled.
      
ManualResetEvent eventX = new ManualResetEvent(false);
      
Console.WriteLine("Queuing {0} items to Thread Pool"MaxCount);
      
Alpha oAlpha = new Alpha(MaxCount);  // Create the work items.
      // Make sure the work items have a reference to the signaling event.
      
oAlpha.eventX eventX;
      
Console.WriteLine("Queue to Thread Pool 0");
      try
      {
         
// Queue the work items, which has the added effect of checking
         // which OS is running.
         
ThreadPool.QueueUserWorkItem(new WaitCallback(oAlpha.Beta),
            new 
SomeState(0));
         
W2K true;
      }
      catch (
NotSupportedException)
      {
         
Console.WriteLine("These API's may fail when called on a non-Windows 2000 system.");
         
W2K false;
      }
      if (
W2K)  // If running on an OS which supports the ThreadPool methods.
      
{
         for (
int iItem=1;iItem MaxCount;iItem++)
         {
            
// Queue the work items:
            
Console.WriteLine("Queue to Thread Pool {0}"iItem);
            
ThreadPool.QueueUserWorkItem(new WaitCallback(oAlpha.Beta),new SomeState(iItem));
         }
         
Console.WriteLine("Waiting for Thread Pool to drain");
         
// The call to exventX.WaitOne sets the event to wait until
         // eventX.Set() occurs.
         // (See oAlpha.Beta).
         // Wait until event is fired, meaning eventX.Set() was called:
         
eventX.WaitOne(Timeout.Infinite,true);
         
// The WaitOne won't return until the event has been signaled.
         
Console.WriteLine("Thread Pool has been drained (Event fired)");
         
Console.WriteLine();
         
Console.WriteLine("Load across threads");
         foreach(
object o in oAlpha.HashCount.Keys)
            
Console.WriteLine("{0} {1}"ooAlpha.HashCount[o]);
      }
      return 
0;
   }

Resultados del ejemplo

Nota Estos resultados varían de un equipo a otro.
Thread Pool Sample:
Queuing 10 items to Thread Pool
Queue to Thread Pool 0
Queue to Thread Pool 1
...
...
Queue to Thread Pool 9
Waiting for Thread Pool to drain
98 0 :
HashCount.Count==0, Thread.CurrentThread.GetHashCode()==98
100 1 :
HashCount.Count==1, Thread.CurrentThread.GetHashCode()==100
98 2 :
...
...
Setting eventX
Thread Pool has been drained (Event fired)

Load across threads
101 2
100 3
98 4
102 1
Ejemplo 4: utilizar el objeto de exclusión mutua

Se puede utilizar un objeto de exclusión mutua (mutex) con el fin de proteger un recurso compartido del acceso simultáneo por parte de múltiples subprocesos o procesos. El estado de un objeto de exclusión mutua se establece como señalizado, en cuyo caso no es propiedad de ningún subproceso, o no señalizado, en cuyo caso sí es propiedad de un subproceso. Sólo un subproceso a la vez puede tener la propiedad de un objeto de exclusión mutua. Por ejemplo, para impedir que dos subprocesos escriban en una zona de memoria compartida al mismo tiempo, cada subproceso espera a tener la propiedad de un objeto de exclusión mutua antes de ejecutar el código que obtiene acceso a la memoria. Después de escribir en la zona de memoria compartida, el subproceso libera el objeto.

Ese ejemplo muestra cómo utilizar las clases Mutex, AutoResetEvent y WaitHandle al procesar los subprocesos. También muestra el uso de los métodos utilizados al procesar el objeto de exclusión mutua.

Código PHP:
// Mutex.cs
// Mutex object example
using System;
using System.Threading;

public class 
MutexSample
{
   static 
Mutex gM1;
   static 
Mutex gM2;
   const 
int ITERS 100;
   static 
AutoResetEvent Event1 = new AutoResetEvent(false);
   static 
AutoResetEvent Event2 = new AutoResetEvent(false);
   static 
AutoResetEvent Event3 = new AutoResetEvent(false);
   static 
AutoResetEvent Event4 = new AutoResetEvent(false);
   
   public static 
void Main(String[] args)
   {
      
Console.WriteLine("Mutex Sample ...");
      
// Create Mutex initialOwned, with name of "MyMutex".
      
gM1 = new Mutex(true,"MyMutex");
      
// Create Mutex initialOwned, with no name.
      
gM2 = new Mutex(true);
      
Console.WriteLine(" - Main Owns gM1 and gM2");

      
AutoResetEvent[] evs = new AutoResetEvent[4];
      
evs[0] = Event1;    // Event for t1
      
evs[1] = Event2;    // Event for t2
      
evs[2] = Event3;    // Event for t3
      
evs[3] = Event4;    // Event for t4

      
MutexSample tm = new MutexSample( );
      
Thread t1 = new Thread(new ThreadStart(tm.t1Start));
      
Thread t2 = new Thread(new ThreadStart(tm.t2Start));
      
Thread t3 = new Thread(new ThreadStart(tm.t3Start));
      
Thread t4 = new Thread(new ThreadStart(tm.t4Start));
      
t1.Start( );   // Does Mutex.WaitAll(Mutex[] of gM1 and gM2)
      
t2.Start( );   // Does Mutex.WaitOne(Mutex gM1)
      
t3.Start( );   // Does Mutex.WaitAny(Mutex[] of gM1 and gM2)
      
t4.Start( );   // Does Mutex.WaitOne(Mutex gM2)

      
Thread.Sleep(2000);
      
Console.WriteLine(" - Main releases gM1");
      
gM1.ReleaseMutex( );  // t2 and t3 will end and signal

      
Thread.Sleep(1000);
      
Console.WriteLine(" - Main releases gM2");
      
gM2.ReleaseMutex( );  // t1 and t4 will end and signal

      // Waiting until all four threads signal that they are done.
      
WaitHandle.WaitAll(evs); 
      
Console.WriteLine("... Mutex Sample");
   }

   public 
void t1Start( )
   {
      
Console.WriteLine("t1Start started,  Mutex.WaitAll(Mutex[])");
      
Mutex[] gMs = new Mutex[2];
      
gMs[0] = gM1;  // Create and load an array of Mutex for WaitAll call
      
gMs[1] = gM2;
      
Mutex.WaitAll(gMs);  // Waits until both gM1 and gM2 are released
      
Thread.Sleep(2000);
      
Console.WriteLine("t1Start finished, Mutex.WaitAll(Mutex[]) satisfied");
      
Event1.Set( );      // AutoResetEvent.Set() flagging method is done
   
}

   public 
void t2Start( )
   {
      
Console.WriteLine("t2Start started,  gM1.WaitOne( )");
      
gM1.WaitOne( );    // Waits until Mutex gM1 is released
      
Console.WriteLine("t2Start finished, gM1.WaitOne( ) satisfied");
      
Event2.Set( );     // AutoResetEvent.Set() flagging method is done
   
}

   public 
void t3Start( )
   {
      
Console.WriteLine("t3Start started,  Mutex.WaitAny(Mutex[])");
      
Mutex[] gMs = new Mutex[2];
      
gMs[0] = gM1;  // Create and load an array of Mutex for WaitAny call
      
gMs[1] = gM2;
      
Mutex.WaitAny(gMs);  // Waits until either Mutex is released
      
Console.WriteLine("t3Start finished, Mutex.WaitAny(Mutex[])");
      
Event3.Set( );       // AutoResetEvent.Set() flagging method is done
   
}

   public 
void t4Start( )
   {
      
Console.WriteLine("t4Start started,  gM2.WaitOne( )");
      
gM2.WaitOne( );   // Waits until Mutex gM2 is released
      
Console.WriteLine("t4Start finished, gM2.WaitOne( )");
      
Event4.Set( );    // AutoResetEvent.Set() flagging method is done
   
}

Resultados del ejemplo

Mutex Sample ...
- Main Owns gM1 and gM2
t1Start started, Mutex.WaitAll(Mutex[])
t2Start started, gM1.WaitOne( )
t3Start started, Mutex.WaitAny(Mutex[])
t4Start started, gM2.WaitOne( )
- Main releases gM1
t2Start finished, gM1.WaitOne( ) satisfied
t3Start finished, Mutex.WaitAny(Mutex[])
- Main releases gM2
t1Start finished, Mutex.WaitAll(Mutex[]) satisfied
t4Start finished, gM2.WaitOne( )
... Mutex Sample
Nota El resultado del ejemplo puede variar de un equipo a otro y de una ejecución a otra. La velocidad y el sistema operativo del equipo en que se ejecute el ejemplo pueden afectar al orden del resultado. En entornos multiproceso, los eventos pueden no darse en el orden esperado.
Vea también
#2
muy buen tutorial
#3
Muy interesante y bien explicado! gracias!
#4
por favor envuelve el codigo en las etiquetas correspondientes para evitar problemas. Esta vez lo hago yo, pero hazlo tu la proxima Lengua
WWW


Posibles temas similares...
Tema Autor Respuestas Vistas Último mensaje
Información [Tutorial] Certificado SSL Gratis StartSSL 2016 Tutorial DarkMaster 26 5,379 28-04-2016, 03:39 AM
Último mensaje: Lob3zNo
Bombilla [Tutorial] SSL Gratis, Conseguir e Instalar Certificado DarkMaster 16 924 06-01-2016, 01:32 AM
Último mensaje: DarkMaster
  [PUBLICO] Tutorial Botones con perspectiva 3D AngelKrak 0 257 17-01-2015, 05:44 AM
Último mensaje: AngelKrak
  [Tutorial] Aumentar el Tamaño Máximo al Cargar Archivos con PHP y Apache papanoel 0 694 22-01-2014, 04:38 AM
Último mensaje: papanoel
  Tutorial Css Primera Parte para phpost JNeutron 4 1,074 24-02-2013, 04:01 AM
Último mensaje: Echizen
  [TUTORIAL] Conexión a una Base de Datos desde [PHP] lapipichapa 0 497 15-02-2013, 05:52 PM
Último mensaje: lapipichapa
  Tutorial de .htaccess | Control de acceso a carpetas diringax 11 1,479 13-01-2013, 12:28 PM
Último mensaje: papi
  [TUTORIAL] Como evitar el Hotlinkeo (robo de imágenes) Taquion 8 1,719 12-01-2013, 05:50 PM
Último mensaje: natestale
  Tutorial | Crear Sistema de Login PHP diringax 13 1,755 18-12-2012, 01:49 AM
Último mensaje: BrayanFG
  [Tutorial] Dominios virtuales para localhost Alan71 25 2,230 18-12-2012, 01:44 AM
Último mensaje: BrayanFG



Usuarios navegando en este tema: 1 invitado(s)