Su ejemplo es muy interesante: muestra los efectos secundarios del procesamiento en paralelo. Para responder a su pregunta, y para que sea más fácil ver los efectos secundarios, he modificado ligeramente su ejemplo:
using System;
using System.Threading;
using System.Diagnostics;
public class Program
{
public static void Main()
{
(new Example()).Main();
}
}
public class Example
{
public void Main()
{
System.Timers.Timer t = new System.Timers.Timer(10);
t.Enabled = true;
t.Elapsed += (sender, args) => c();
Console.ReadLine(); t.Enabled = false;
}
int t = 0;
int h = 0;
public void c()
{
h++;
new Thread(() => doWork(h)).Start();
}
public void doWork(int h2)
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
t++;
Console.WriteLine("h={0}, h2={1}, threads={2} [start]", h, h2, t);
Thread.Sleep(3000);
}
finally
{
sw.Stop();
var tim = sw.Elapsed;
var elapsedMS = tim.Seconds * 1000 + tim.Milliseconds;
t--;
Console.WriteLine("h={0}, h2={1}, threads={2} [end, sleep time={3} ms] ", h, h2, t, elapsedMS);
}
}
}
Lo he modificado aquí es la siguiente:
- intervalo del temporizador es ahora 10 ms, los hilos todavía tienen 3000 ms. El efecto es que mientras los hilos están durmiendo, se crearán nuevos hilos
- He añadido varialbe
t
, que cuenta el número de hilos actualmente activos (se incrementa cuando el hilo comienza y disminuye justo antes de que termine el hilo)
- he añadido 2 declaraciones de volteo, imprimiendo el comienzo de la rosca y el extremo del hilo
- Por último, he dado el parámetro de la función
doWork
un nombre diferente (h2), lo que permite ver el valor de la variable subyacente h
Ahora es intersting ver la salida de este programa modificado en LinqPad (tenga en cuenta los valores no siempre son los mismos que están en función de las condiciones de la carrera de las discusiones iniciadas):
h=1, h2=1, threads=1 [start]
h=2, h2=2, threads=2 [start]
h=3, h2=3, threads=3 [start]
h=4, h2=4, threads=4 [start]
h=5, h2=5, threads=5 [start]
...
h=190, h2=190, threads=190 [start]
h=191, h2=191, threads=191 [start]
h=192, h2=192, threads=192 [start]
h=193, h2=193, threads=193 [start]
h=194, h2=194, threads=194 [start]
h=194, h2=2, threads=192 [end]
h=194, h2=1, threads=192 [end]
h=194, h2=3, threads=191 [end]
h=195, h2=195, threads=192 [start]
Creo que los valores hablan por sí mismos: Lo que está sucediendo es que cada 10 ms un nuevo el hilo se inicia, mientras que otros todavía están durmiendo. También es interesante ver que h no siempre es igual a h2, especialmente no si se inician más hilos mientras que otros están durmiendo. El número de subprocesos (variable t) se estabiliza después de un tiempo, es decir, se ejecuta alrededor de 190-194.
Se podría argumentar, que tenemos que poner cerraduras en las variables T y H, por ejemplo
readonly object o1 = new object();
int _t=0;
int t {
get {int tmp=0; lock(o1) { tmp=_t; } return tmp; }
set {lock(o1) { _t=value; }}
}
Mientras que es un enfoque más limpio, que no cambió el efecto se muestra en este ejemplo.
Ahora, con el fin de demostrar que cada hilo realmente duerme 3000 ms (= 3s), vamos a añadir un Stopwatch
para el subproceso de trabajo doWork
:
public void doWork(int h2)
{
Stopwatch sw = new Stopwatch(); sw.Start();
try
{
t++; string.Format("h={0}, h2={1}, threads={2} [start]",
h, h2, t).Dump();
Thread.Sleep(3000); }
finally {
sw.Stop(); var tim = sw.Elapsed;
var elapsedMS = tim.Seconds*1000+tim.Milliseconds;
t--; string.Format("h={0}, h2={1}, threads={2} [end, sleep time={3} ms] ",
h, h2, t, elapsedMS).Dump();
}
}
Para una limpieza adecuada de los hilos, vamos a desactivar el temporizador después de la ReadLine
de la siguiente manera:
Console.ReadLine(); t.Enabled=false;
Esto le permite ver lo que sucede si no hay más hilos están empezando, después de pulsar ENTER:
...
h=563, h2=559, threads=5 [end, sleep time=3105 ms]
h=563, h2=561, threads=4 [end, sleep time=3073 ms]
h=563, h2=558, threads=3 [end, sleep time=3117 ms]
h=563, h2=560, threads=2 [end, sleep time=3085 ms]
h=563, h2=562, threads=1 [end, sleep time=3054 ms]
h=563, h2=563, threads=0 [end, sleep time=3053 ms]
Puede ver que todas terminan una tras otra como se esperaba y durmieron aproximadamente 3s (o 3000ms).
No veo el problema. Lo que sucede es exactamente lo que esperas de un escenario de subprocesos múltiples. – leppie
Cuidado: *** ¡Es una trampa! *** Lo que ves no tiene mucho que ver con lo que querías lograr, creo. –
No veo ningún problema aquí, cuando generas hilos con tres segundos de sueño en cada uno, pero el desove ocurre una vez por segundo, entonces tienes un retraso inicial ya que el primero tiene que "esperar" los tres segundos para pasar, pero todos los demás lo siguen con un desplazamiento de un segundo. – Gorgsenegger