如何激发对共享资源的模拟访问



我正在创建一个在输入上执行顺序处理的组件。由于它将在几个不同的过程中托管,因此我需要它是安全的。首先,我故意从代码中省略了线程安全性。现在是时候介绍了。

首先,我想引起一个错误,但不能。这是处理引擎的代码的简化版本:

public Document DoOrchestration(Document input)
{
    Document output = new Document();
    foreach (var orchestrationStep in m_OrchestrationSteps)
    {
        var processor = GetProcessor(orchestrationStep).Clone();
        output = processor.Process(input);
        input = output;
    }
    return output;
}

处理器可以由我组织中的其他人开发,其中可能包括一些复杂的初始化。它们也可能是线程不安全的,因此我使用原型模式来获取独特的实例,以避免在这些情况下进行线程问题。

要测试此功能,我使用了以下代码:

for (int i = 0; i < 20000; i++)
{
    Thread t = new Thread(() => TestOrchestration(i));
    t.Start();
}
void TestOrchestration(int number)
{
    Document doc = new Document(string.Format("Test {0}", number));
    doc = DoOrchestration(doc);
    if (doc.ToString().Substring(0,35) != strExpectedResult)
    {
        System.Console.WriteLine("Error: {0}", doc.ToString();
    }
}

我希望某些线程会与另一个线程相撞并混合结果,但令我惊讶的是没有发生。

对此可能有一个简单且逻辑上的解释,但它使我感到不安。或者只是代码太简单,无法同时导致两个线程摆弄输入/输出变量?

查看国际象棋。

国际象棋是在并发中查找和复制的Heisenbugs的工具 程式。国际象棋反复进行并发测试,以确保每一个 跑步需要不同的交织。如果交错导致 错误,国际象棋可以重现交错以改进调试。 国际象棋可用于托管和本地程序。

我假设,由于测试功能的简单性,您的线程甚至没有时间在上一个工作完成之前大量产生。考虑在开始计算步骤之前,请考虑使用屏障来允许所有线程产卵。另外,您将需要考虑增加测试用例的复杂性,例如,在同一循环中执行相同的操作(启动线程很昂贵),并允许其他内核完成他们的工作资源争夺。

通常,可以通过在更长的时间内快速访问相同资源来引起资源争议,您的测试案例似乎不允许这样做。顺便说一句,我强烈建议您考虑到线程安全的设计,而不是以后引入。使用代码时,您对资源访问模式的理解比以后分析代码时所拥有的。

您可以使用 ManualResetEvent同时延续任何等待线程。

我认为您的测试功能在下一个线程启动之前几乎完成。您可以使所有线程在调用编排功能之前在ManualReseteventslim上等待,然后设置ManualReseteventslim
这样一来,您的所有线程都会尝试同时调用编排。

同样,如果所有线程在几乎同一时间

ManualResetEventSlim manualEvent = new ManualResetEventSlim (false);
for (int i = 0; i < 20000; i++)
{
    Thread t = new Thread(() => TestOrchestration(i));
    t.Start();
}
manualEvent.Set();
void TestOrchestration(int number)
{
    manualEvent.Wait();
    Document doc = new Document(string.Format("Test {0}", number));
    doc = DoOrchestration(doc);
    if (doc.ToString().Substring(0,35) != strExpectedResult)
    {
        System.Console.WriteLine("Error: {0}", doc.ToString();
    }
}

最新更新