C# 线程之间基于回合的同步

C# 线程之间基于回合的同步,c#,multithreading,c#-4.0,thread-safety,C#,Multithreading,C# 4.0,Thread Safety,我试图找到一种方法来同步具有以下条件的多个线程: 有两种类型的线程: 执行无限循环以进行循环计算的单个“循环”线程 多个短期线程不是由主线程启动的 循环线程在每个循环/循环迭代之间有一个睡眠持续时间 允许在循环线程的周期间休眠期间执行其他线程: 应该阻止在活动循环期间尝试执行的任何其他线程 循环线程将等待所有其他已经执行的线程完成 下面是我想做的一个基本例子: // Somewhere in the code: ManualResetEvent manualResetEvent = n

我试图找到一种方法来同步具有以下条件的多个线程:

  • 有两种类型的线程:
  • 执行无限循环以进行循环计算的单个“循环”线程
  • 多个短期线程不是由主线程启动的
  • 循环线程在每个循环/循环迭代之间有一个睡眠持续时间
  • 允许在循环线程的周期间休眠期间执行其他线程:
    • 应该阻止在活动循环期间尝试执行的任何其他线程
    • 循环线程将等待所有其他已经执行的线程完成
下面是我想做的一个基本例子:

// Somewhere in the code:
ManualResetEvent manualResetEvent = new ManualResetEvent(true); // Allows external call
CountdownEvent countdownEvent = new CountdownEvent(1); // Can't AddCount a CountdownEvent with CurrentCount = 0

void ExternallyCalled()
{
    manualResetEvent.WaitOne(); // Wait until CyclicCalculations is having its beauty sleep

    countdownEvent.AddCount(); // Notify CyclicCalculations that it should wait for this method call to finish before starting the next cycle

    Thread.Sleep(1000); // TODO: Replace with actual method logic

    countdownEvent.Signal(); // Notify CyclicCalculations that this call is finished
}

void CyclicCalculations()
{
    while (!stopCyclicCalculations)
    {
        manualResetEvent.Reset(); // Block all incoming calls to ExternallyCalled from this point forward

        countdownEvent.Signal(); // Dirty workaround for the issue with AddCount and CurrentCount = 0
        countdownEvent.Wait(); // Wait until all of the already executing calls to ExternallyCalled are finished

        countdownEvent.Reset(); // Reset the CountdownEvent for next cycle.

        Thread.Sleep(2000); // TODO: Replace with actual method logic

        manualResetEvent.Set(); // Unblock all threads executing ExternallyCalled

        Thread.Sleep(1000); // Inter-cycles delay
    }
}
显然,这是行不通的。不能保证在
manualResetEvent.WaitOne()之间不会有任何线程执行外部调用的
countdownEvent.AddCount()在主线程被
倒计时事件释放时

我想不出一个简单的方法来做我想做的事情,而我在长时间搜索后发现的几乎所有东西都与生产者/消费者同步有关,我在这里无法应用

编辑:解决方案

根据公认的答案,这是如何做我想做的事情的要点:

// Somewhere in the code:
ReaderWriterLockSlim readerWriterLockSlim = new ReaderWriterLockSlim();

void ExternallyCalled()
{
    readerWriterLockSlim.EnterReadLock();

    Thread.Sleep(1000); // TODO: Replace with actual method logic

    readerWriterLockSlim.ExitReadLock();
}

void CyclicCalculations()
{
    while (!stopCyclicCalculations)
    {
        readerWriterLockSlim.EnterWriteLock();

        Thread.Sleep(2000); // TODO: Replace with actual method logic

        readerWriterLockSlim.ExitWriteLock();

        Thread.Sleep(1000); // Inter-cycles delay
    }
}

看起来你需要一个电话。您的循环线程是“编写器”,其他线程是“读取器”。

看起来您需要一个。你的循环线程是“writer”,其他线程是“readers”。

完美。正是我需要的。在阅读了一个示例后,我错误地忽略了这种类型的锁,因为它似乎不适合我。我将更新我的问题来展示它是如何简单地用于将来的引用。@ AAMUS,这确实是你需要的代码,但是我会考虑使用一个尝试最后块,如下所示,例如对于读者:<代码> Reader WrrordLoxLim.CaleReadLok();试试{/*随便*/}最后{readerWriterLockSlim.ExitWriteLock();}
。如果EnternallyCalled是线程上运行的唯一代码,那也没关系,因为如果出现未处理的异常,程序将崩溃,但这是一个习惯,我相信这是一个好习惯:确保释放锁。完美。正是我需要的。在阅读了一个示例后,我错误地忽略了这种类型的锁,因为它似乎不适合我。我将更新我的问题来展示它是如何简单地用于将来的引用。@ AAMUS,这确实是你需要的代码,但是我会考虑使用一个尝试最后块,如下所示,例如对于读者:<代码> Reader WrrordLoxLim.CaleReadLok();试试{/*随便*/}最后{readerWriterLockSlim.ExitWriteLock();}
。如果EnternallyCalled是线程上运行的唯一代码,这并不重要,因为程序在发生未处理的异常时会崩溃,但这是一个习惯,我相信这是一个好习惯:确保释放锁。