4

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

首先,我想一开始就引发一个错误,但没能做到。这是处理引擎代码的简化版本:

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

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

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

4

4 回答 4

1

查看国际象棋

CHESS 是一种用于在并发程序中查找和重现 Heisenbugs 的工具。CHESS 反复运行并发测试,确保每次运行都采用不同的交错。如果交错导致错误,CHESS 可以重现交错以改进调试。CHESS 可用于托管程序和本机程序。

于 2012-10-19T06:40:41.140 回答
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();
    }
}
于 2012-10-19T06:49:38.757 回答
0

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

于 2012-10-19T09:45:49.653 回答
0

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

通常,在较长时间内快速访问同一资源可能会引发资源争用,您的测试用例似乎不允许这样做。顺便说一句,我强烈建议您在设计时考虑到线程安全,而不是稍后再介绍。使用代码时,您对资源访问模式的理解比在稍后阶段分析代码时要好。

于 2012-10-19T06:43:41.593 回答