C# 监控多线程。处理后的计时器

C# 监控多线程。处理后的计时器,c#,.net,multithreading,timer,thread-safety,C#,.net,Multithreading,Timer,Thread Safety,我有一个进程,它创建一个计时器的动态列表(System.Threading.Timer),并继续运行,直到收到终止信号。收到终止信号后,我希望完成任何现有计时器回调(见下文): 添加以下内容: (注意:我创建了一个包含计时器和相关数据的ThreadContext类) private void WaitOnExecutingThreads() { var waiters=新列表(); WaitOrTimerCallback IsRunning=(x,timeout)=>{if(timeout){L

我有一个进程,它创建一个计时器的动态列表(System.Threading.Timer),并继续运行,直到收到终止信号。收到终止信号后,我希望完成任何现有计时器回调(见下文):

添加以下内容: (注意:我创建了一个包含计时器和相关数据的ThreadContext类)

private void WaitOnExecutingThreads()
{
var waiters=新列表();
WaitOrTimerCallback IsRunning=(x,timeout)=>{if(timeout){Log(x+“仍在运行”);};
foreach(var threadContext in_threadContexts)
{
var onWait=新手动重置事件(错误);
threadContext.Timer.Dispose(onWait);
RegisterWaitForSingleObject(onWait,IsRunning,threadContext.ThreadInfo.Id,new TimeSpan(0,0,30),false);
waiters.Add(onWait);
}
WaitHandle.WaitAll(waiters.ToArray());
ForEach(x=>x.Dispose());
}
我觉得在C#.NET4.0中,这应该是一项直截了当的任务。在我的简单单元测试中,我的IsRunning回调在等待之后触发了很多次。在此调用之后,我不执行任何进一步的执行。但是我写了很多我不太习惯的代码,感觉这样会失败

有没有更简单的解决办法,或者我误解了什么

更新 根据Peter R.的建议,我提出了以下建议。允许它有更多的代码行,但我不必注册单个线程对象。如果处理后所有线程仍在执行,我将休眠10秒,然后再次检查此示例

    private void WaitOnExecutingThreads()
    {
        foreach (var threadContext in _threadContexts)
        {
            threadContext.DisposeWaiter = new ManualResetEvent(false);
            threadContext.Timer.Dispose(threadContext.DisposeWaiter);
        }

        while(_threadContexts.Count > 0)
        {
            for(var i = 0; i < _threadContexts.Count; i++)
            {
                var threadContext = _threadContexts[i];
                var isComplete = threadContext.DisposeWaiter.WaitOne(0);
                if(isComplete)
                {
                    Console.WriteLine(string.Format("{0}: {1} has completed", DateTime.Now, threadContext.Name));
                    _threadContexts.RemoveAt(i);
                }
                else
                {
                    Console.WriteLine(string.Format("{0}: {1} is still running", DateTime.Now, threadContext.Name));
                }
            }

            if (_threadContexts.Count > 0)
            {
                Thread.Sleep(new TimeSpan(0, 0, 10));
            }
        }
    }
....
public class ThreadContext
{
    public string Name { get; set; }
    public Timer Timer { get; set; }
    public WaitHandle DisposeWaiter { get; set; }
}
private void WaitOnExecutingThreads()
{
foreach(var threadContext in_threadContexts)
{
threadContext.DisposeWaiter=新的手动重置事件(false);
threadContext.Timer.Dispose(threadContext.DisposeWaiter);
}
而(_threadContexts.Count>0)
{
对于(变量i=0;i<\u threadContexts.Count;i++)
{
var threadContext=_threadContexts[i];
var isComplete=threadContext.DisposeWaiter.WaitOne(0);
如果(完成)
{
WriteLine(string.Format(“{0}:{1}已完成”,DateTime.Now,threadContext.Name));
_删除(i);
}
其他的
{
WriteLine(string.Format(“{0}:{1}仍在运行”,DateTime.Now,threadContext.Name));
}
}
如果(_threadContexts.Count>0)
{
睡眠(新的时间跨度(0,0,10));
}
}
}
....
公共类线程上下文
{
公共字符串名称{get;set;}
公共计时器{get;set;}
公共WaitHandle DisposeWaiter{get;set;}
}

_

如果处理程序尚未完成,则不会发出手动重置事件的信号。因此,您可以简单地测试事件是否处于信号状态。i、 e

var isComplete = waiters[0].WaitOne(0);

如果处理程序尚未完成,则不会发出ManualResetEvents的信号。因此,您可以简单地测试事件是否处于信号状态。i、 e

var isComplete = waiters[0].WaitOne(0);

您好,Peter,我可以使用ThreadPool.RegisterWaitForSingleObject验证回调是否完成。你是说我应该在IsRunning委托中使用上面的代码吗?我正在考虑换成一个系统。计时器,但我还没有玩过它。我真的不喜欢调用ThreadPool.RegisterWaitForSingleObject。这似乎有很多开销。参数为0的WaitOne调用实际上并不等待。i、 它等待0毫秒,这意味着它实际上只是给你运行状态…嗨,彼得,回到这里,我能够清楚地看到你的建议。我挂断了RegisterWaitForSingleObject的电话。我已经有了waitevents的集合,然后我可以继续检查主线程中还有谁在运行。这将消除WaitHandle.WaitAll调用,使其更加简单。除非您想更新答案,否则我将发布解决方案的更新。谢谢你的帮助!您好,Peter,我可以使用ThreadPool.RegisterWaitForSingleObject验证回调是否完成。你是说我应该在IsRunning委托中使用上面的代码吗?我正在考虑换成一个系统。计时器,但我还没有玩过它。我真的不喜欢调用ThreadPool.RegisterWaitForSingleObject。这似乎有很多开销。参数为0的WaitOne调用实际上并不等待。i、 它等待0毫秒,这意味着它实际上只是给你运行状态…嗨,彼得,回到这里,我能够清楚地看到你的建议。我挂断了RegisterWaitForSingleObject的电话。我已经有了waitevents的集合,然后我可以继续检查主线程中还有谁在运行。这将消除WaitHandle.WaitAll调用,使其更加简单。除非您想更新答案,否则我将发布解决方案的更新。谢谢你的帮助!
    private void WaitOnExecutingThreads()
    {
        foreach (var threadContext in _threadContexts)
        {
            threadContext.DisposeWaiter = new ManualResetEvent(false);
            threadContext.Timer.Dispose(threadContext.DisposeWaiter);
        }

        while(_threadContexts.Count > 0)
        {
            for(var i = 0; i < _threadContexts.Count; i++)
            {
                var threadContext = _threadContexts[i];
                var isComplete = threadContext.DisposeWaiter.WaitOne(0);
                if(isComplete)
                {
                    Console.WriteLine(string.Format("{0}: {1} has completed", DateTime.Now, threadContext.Name));
                    _threadContexts.RemoveAt(i);
                }
                else
                {
                    Console.WriteLine(string.Format("{0}: {1} is still running", DateTime.Now, threadContext.Name));
                }
            }

            if (_threadContexts.Count > 0)
            {
                Thread.Sleep(new TimeSpan(0, 0, 10));
            }
        }
    }
....
public class ThreadContext
{
    public string Name { get; set; }
    public Timer Timer { get; set; }
    public WaitHandle DisposeWaiter { get; set; }
}
var isComplete = waiters[0].WaitOne(0);