你的例子非常有趣 - 它显示了并行处理的副作用。要回答你的问题,并使其更容易看到的副作用,我稍微修改您的示例:
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);
}
}
}
我在这里修改如下:
- 计时器间隔为现在10毫秒,线程仍然有3000毫秒。其效果是,当线程正在休眠时,将创建新线程
- 我已经添加了varialbe
t
,它计算当前正在活动的线程数(线程在线程结束之前线程开始和减少时会增加)
- 我已经添加了2个转储语句,打印出线程开始和线程结束
- 最后,我已经给函数
doWork
的参数一个不同的名称(h2),它允许查看底层变量的值h
现在看到这个修改程序的输出在LinqPad(注意,因为他们要取决于启动线程的竞争条件的值并不总是相同):
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]
我觉得值,不言自明:正在发生的事情是,每10毫秒新线程启动,而其他人仍在睡觉。另外有趣的是,看到h并不总是等于h2,特别是当更多的线程开始而其他人正在睡觉时。线数(变量t)在稳定之后,即在190-194左右运行。
你可能会说,我们需要把门锁上的变量t与H,例如
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; }}
}
虽然这是一个更简洁的方法,它并没有改变在这个例子中所示的效果。现在
,为了证明每个线程真的睡3000ms(= 3秒),让我们添加一个Stopwatch
的工作线程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();
}
}
对于线程的适当的清理,让我们关闭计时器在ReadLine
依次如下:
Console.ReadLine(); t.Enabled=false;
这使您可以看到,如果没有更多的线程开始发生什么事,你按下之后按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]
你可以看到他们都被终止一前一后的预期和他们睡觉3s左右(或3000ms)。
我没看到问题。发生的事情正是您对多线程场景的期望。 – leppie
注意:***这是一个陷阱! ***你所看到的与你想达到的目标无关,我相信。 –
我也没有在这里看到任何问题 - 当你在每次产生三秒睡眠的线程产卵时,但产卵每秒发生一次,那么你有一个最初的延迟,因为第一个必须“等待”三秒钟通过,但所有其他人正在跟随一秒钟的偏移量。 – Gorgsenegger