2012-03-27 29 views
1

我有一个对象“守则”的列表:执行线程的列表

List<Code> listCodes = new List<Code>(); 

我需要执行一个线程列表内的每个代码,但我不知道该怎么做,因为我试着这样做:

foreach(Code c in listCodes) 
{ 
    Thread tr = new Thread(delegate() { 
     Execute(c.CodeLine); 
    }); 
} 

这的foreach是一个计时器,因为这些代码会被执行所有的时间,但是当我做相同的代码被执行,即使第一次执行了很多次没有完成,如果代码需要5秒的时间来执行和完成,并且定时器是500ms,它将被执行例如,如果我在5秒后禁用定时器10次,例如。

我想不出什么来执行列表中的代码,每个代码在他们的线程中,但我想要执行代码0的线程(例如),只有当它在执行后完成。

谢谢。

+1

计时器正在很丑陋。如前所述,没有理由,你也可以在线程内循环,并使用ManualResetEvent来停止循环。 – 2012-03-27 02:38:41

回答

4

System.Threading.Monitor.TryEnter是完美的人选:

foreach(Code c in listCodes) { 
    Code a = c; 

    new Thread(delegate() { 
     if(Monitor.TryEnter(a)) { 
      Execute(a.CodeLine); 
      Monitor.Exit(a); 
     } 
    }) { IsBackground = true }.Start(); 
} 

它所做的是试图获取Code对象的排它锁。如果它不能(即Code已经执行),那么什么都不会发生;否则,锁被获取,并在执行完成时释放。

+0

在线程开始执行的时候不会释放排它锁吗?控制权在Execute()后立即返回给调用者。 – 2012-03-27 01:18:52

+0

@EricJ:不,锁定代码在线程内,而不是循环。 – Ryan 2012-03-27 01:19:19

+0

LOL错过了。所以现在习惯了TPL,我读过了显式的线程创建。 – 2012-03-27 01:22:48

0

您需要实际等待Thread s完成。你可以通过拨打电话Join

List<Thread> threads = new List<Threads>(); 

foreach(Code c in listCodes) 
{ 
    Thread tr = new Thread(delegate() { 
     Execute(c.CodeLine); 
    }); 
    threads.Add(tr); 
} 

foreach(Thread tr in threads) 
{ 
    tr.Join(); 
} 

这些都在你的外部计时器中。

+1

这将阻塞主线程,直到所有其他线程完成,这将需要在可以阻塞的线程上执行代码线程。 – 2012-03-27 01:21:31

1

我认为使用Thread这样的效率很低,应该用Task代替。

在C#5,我会做这样的:

private static async Task RunCode(Code code, TimeSpan delay) 
{ 
    while (!Stopped) 
    { 
     var delayTask = Task.Delay(delay); 

     Execute(code.CodeLine); 

     await delayTask; 
    } 
} 

然后启动一次(即不在一个定时器):

foreach (Code c in listCodes) 
{ 
    Task.Run(() => RunCode(c, TimeSpan.FromMilliseconds(1000))); 
}