如何激发对共享资源的同时访问?

时间:2012-10-19 06:29:29

标签: c# multithreading locking

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

首先,我想引发一个错误,但是无法做到。以下是处理引擎代码的简化版本:

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;
}

处理器可以由我组织中的其他人开发,这可能包括一些复杂的初始化。它们也可能是线程不安全的,所以我使用Prototype Pattern来获取它的唯一实例,以避免线程问题。

为了测试这个功能,我使用了以下代码:

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();
    }
}

我预计有些线程会与另一个线程发生冲突并混淆其结果,但令我惊讶的是,这并没有发生。

对此可能有一个简单而合理的解释,但它让我望而却步。或者只是代码太简单而导致两个线程同时摆弄输入/输出变量?

4 个答案:

答案 0 :(得分:1)

查看CHESS

  

CHESS是一种同时发现和复制Heisenbugs的工具   程式。 CHESS反复运行并发测试,确保每一个   run需要不同的交错。如果交错产生一个   错误,CHESS可以重现交错以改进调试。   CHESS适用于托管和本机程序。

答案 1 :(得分:0)

我认为由于测试功能的简单性,你的线程甚至没有时间在前一个完成它的工作之前产生大量的时间。在开始计算步骤之前,请考虑使用barrier允许所有线程生成。此外,您还需要考虑增加测试用例的复杂性,例如通过在同一个循环中执行多个相同的操作(启动一个线程很昂贵,并允许其他内核完成他们的工作,然后再进入资源争夺。

通常,可以通过在较长时间内快速访问相同资源来激发资源争用,您的测试用例似乎不允许这样做。顺便说一句,我强烈建议您考虑线程安全,而不是稍后介绍。使用代码时,您可以更好地理解资源访问模式,而不是在稍后分析代码时。

答案 2 :(得分:0)

我认为你的测试函数在下一个线程启动之前几乎完成了。您可以在调用业务流程函数之前使所有线程在ManualResetEventSlim上等待,然后设置ManualResetEventSlim
这样,所有线程都会尝试同时调用业务流程。

如果所有线程男性管弦乐队几乎同时调用,你也可能不需要20,000个线程来模拟这种行为

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();
    }
}

答案 3 :(得分:0)

您可以使用ManualResetEvent同时继续任意数量的等待线程。