你的例子非常有趣 - 它顯示了並行處理的副作用。要回答你的問題,並使其更容易看到的副作用,我稍微修改您的示例:
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