让所有线程都睡觉

时间:2010-08-24 04:54:53

标签: c# multithreading

我使用新的Parallel.For创建多个线程来执行相同的操作。

如果其中一个线程失败,则表示我工作“太快”,我需要让所有线程休息几秒钟。

有没有办法执行类似Thread.Sleep的东西 - 只能在所有线程上同时执行相同操作?

2 个答案:

答案 0 :(得分:2)

除了Parallel.For位之外,这是问题的直接答案。 这真是一个可怕的模式;你可能应该使用正确的同步机制,让工作线程在没有抢占的情况下偶尔检查是否需要“退回”。 此外,这会使用Thread.SuspendThread.Resume这两个都已弃用,且有充分理由(来自Thread.Suspend):

“不要使用Suspend和Resume方法来同步线程的活动。当你挂起它时,你无法知道线程正在执行什么代码。如果你在安全权限评估期间持有锁时挂起一个线程,AppDomain中的其他线程可能会被阻塞。如果在执行类构造函数时挂起一个线程,AppDomain中尝试使用该类的其他线程将被阻止。死锁很容易发生。“

(未测试的)

public class Worker
{
    private readonly Thread[] _threads;
    private readonly object _locker = new object();
    private readonly TimeSpan _tooFastSuspensionSpan;
    private DateTime _lastSuspensionTime;

    public Worker(int numThreads, TimeSpan tooFastSuspensionSpan)
    {
        _tooFastSuspensionSpan = tooFastSuspensionSpan;
        _threads = Enumerable.Repeat(new ThreadStart(DoWork), numThreads)
                             .Select(ts => new Thread(ts))
                             .ToArray();
    }

    public void Run()
    {
        foreach (var thread in _threads)
        {
            thread.Start();
        }
    }

    private void DoWork()
    {
        while (!IsWorkComplete())
        {
            try
            {
                // Do work here

            }
            catch (TooFastException)
            {
                SuspendAll();
            }
        }

    }

    private void SuspendAll()
    {
        lock (_locker)
        {
            // We don't want N near-simultaneous failures causing a sleep-duration of N * _tooFastSuspensionSpan
            // 1 second is arbitrary. We can't be deterministic about it since we are forcefully suspending threads
            var now = DateTime.Now;
            if (now.Subtract(_lastSuspensionTime) < _tooFastSuspensionSpan + TimeSpan.FromSeconds(1))
                return;

            _lastSuspensionTime = now;

            var otherThreads = _threads.Where(t => t.ManagedThreadId != Thread.CurrentThread.ManagedThreadId).ToArray();

            foreach (var otherThread in otherThreads)
                otherThread.Suspend();

            Thread.Sleep(_tooFastSuspensionSpan);

            foreach (var otherThread in otherThreads)
                otherThread.Resume();
        }
    }

}

答案 1 :(得分:0)

您需要创建工作线程的清单,然后您可以使用Thread.Suspend和Resume方法。请注意,使用Suspend可能很危险(例如,线程可能在挂起之前已获得锁定)。由于这些问题,暂停/恢复被标记为绝对。