Roy*_*mir 54 .net c# multithreading
我有这个代码:
void Main()
{
System.Timers.Timer t = new System.Timers.Timer (1000);
t.Enabled=true;
t.Elapsed+= (sender, args) =>c();
Console.ReadLine();
}
int h=0;
public void c()
{
h++;
new Thread(() => doWork(h)).Start();
}
public void doWork(int h)
{
Thread.Sleep(3000);
h.Dump();
}
Run Code Online (Sandbox Code Playgroud)
我想看看如果间隔为1000毫秒且作业过程为3000毫秒会发生什么.
但是我看到了一个奇怪的行为 - 3000毫秒延迟仅在开始时发生!
如何让每次doWork睡眠时间为3000毫秒?
正如你在这里看到的那样,开始时有3秒的延迟,然后每次迭代1秒.

Mar*_*ell 65
每次计时器滴答时,你都会开始一个线程来做一些睡眠; 该线程完全隔离,计时器将继续每秒触发.实际上,即使你Sleep(3000)进入,计时器也会每秒触发一次c().
你现在拥有的是:
1000 tick (start thread A)
2000 tick (start thread B)
3000 tick (start thread C)
4000 tick (start thread D, A prints line)
5000 tick (start thread E, B prints line)
6000 tick (start thread F, C prints line)
7000 tick (start thread G, D prints line)
8000 tick (start thread H, E prints line)
...
Run Code Online (Sandbox Code Playgroud)
目前还不清楚你要做什么.您可以在不希望它开火时禁用定时器,并在准备好后再次恢复它,但目前还不清楚它的用途是什么Sleep().另一种选择只是一个while带有a 的循环Sleep().简单,并且不涉及大量线程.
Age*_*t_L 15
每秒你都会以3秒的延迟开始新的线程.它发生如下:
如您所见,每个线程都会休眠3秒钟,但每秒都会发生转储.
如何使用线程?像这样:
void Main()
{
new Thread(() => doWork()).Start();
Console.ReadLine();
}
public void doWork()
{
int h = 0;
do
{
Thread.Sleep(3000);
h.Dump();
h++;
}while(true);
}
Run Code Online (Sandbox Code Playgroud)
您的示例非常有趣 - 它显示了并行处理的副作用.为了回答你的问题,并且为了更容易看到副作用,我稍微修改了你的例子:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我在这里修改的内容如下:
t,它计算当前处于活动状态的线程数(当线程开始时它会增加,并且在线程结束之前减少)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]
Run Code Online (Sandbox Code Playgroud)
我认为价值观不言自明:正在发生的事情是每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; }}
}
Run Code Online (Sandbox Code Playgroud)
虽然这是一种更简洁的方法,但它并未改变此示例中显示的效果.
现在,为了证明每个线程确实睡眠时间为3000毫秒(= 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();
}
}
Run Code Online (Sandbox Code Playgroud)
为了正确清理线程,让我们ReadLine按如下方式禁用定时器:
Console.ReadLine(); t.Enabled=false;
Run Code Online (Sandbox Code Playgroud)
这使您可以看到在按下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]
Run Code Online (Sandbox Code Playgroud)
你可以看到他们都按预期一个接一个地被终止,他们睡了大约3s(或3000ms).
您看到此行为的原因很简单:您每秒安排一个新线程,结果在三秒后可见.前四秒你没有看到任何东西; 然后,三秒钟前启动的线程转储; 到那时另一个线程已经睡了两秒钟,而另一个线程已经睡了两秒钟 - 一秒钟.下一个第二个线程#2转储; 然后线程#3,#4等等 - 你每秒都会得到一个打印输出.
如果你想每三秒钟看一次打印输出,你应该每隔三秒安排一个新的线程,你想要任何延迟:初始线程将在三秒内输出加上延迟; 所有后续线程将以三秒为间隔触发.