在写任何锁之前,我应该对多线程问题进行单元测试吗?

Jad*_*ias 8 .net c# tdd multithreading unit-testing

我正在编写一个我知道需要锁的类,因为该类必须是线程安全的.但是,因为我是测试驱动 - 开发我知道在为它创建测试之前我不能编写一行代码.而且我觉得很难做到,因为测试最终会变得非常复杂.在这些情况下你通常做什么?有什么工具可以帮助吗?

这个问题是.NET特定的

有人要求代码:

public class StackQueue
{
    private Stack<WebRequestInfo> stack = new Stack<WebRequestInfo>();
    private Queue<WebRequestInfo> queue = new Queue<WebRequestInfo>();

    public int Count
    {
        get
        {
            return this.queue.Count + this.stack.Count;
        }
    }

    public void Enqueue(WebRequestInfo requestInfo)
    {
        this.queue.Enqueue(requestInfo);
    }

    public void Push(WebRequestInfo requestInfo)
    {
        this.stack.Push(requestInfo);
    }

    private WebRequestInfo Next()
    {
        if (stack.Count > 0)
        {
            return stack.Pop();
        }
        else if (queue.Count > 0)
        {
            return queue.Dequeue();
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 6

好吧,ManualResetEvent在释放门之前,你通常可以使用类似的东西让一些线程进入预期的问题状态......但这只涉及一小部分线程问题.

对于线程错误的更大问题,有CHESS(进行中) - 可能是未来的一个选项.


Esk*_*ola 3

编写多线程代码时,必须比平时更加​​动脑子。您必须对每一行代码进行逻辑推理,无论它是否是线程安全的。这就像证明数学公式的正确性一样 - 您不能仅通过给出公式正确的 N 值的示例来证明“对于所有 N,N + 1 > N”之类的事情。同样,通过编写试图暴露类问题的测试用例来证明类是线程安全的是不可能的。通过测试只能证明有故障,但不能证明没有故障。

您能做的最好的事情就是最大限度地减少对多线程代码的需求。优选地,应用程序不应具有多线程代码(例如,通过依赖线程安全库和合适的设计模式),或者应将其限制在非常小的区域内。您的StackQueue类看起来很简单,因此您只需稍加思考就可以使其安全地成为线程安全的。

假设StackQueue实现是线程安全的(我不知道.NET的库),你只需要使其Next()线程安全。Count已经是线程安全的,因为没有客户端可以在不使用基于客户端的锁定的情况下安全地使用从它返回的值 -方法之间的状态依赖关系会破坏代码。

Next()不是线程安全的,因为它在方法之间具有状态依赖性。如果线程 T1 和 T2stack.Count同时调用并且返回 1,则其中一个将获得 的值stack.Pop(),但另一个将stack.Pop()在堆栈为空时调用(然后出现抛出异常InvalidOperationException)。您将需要一个具有非阻塞版本的堆栈和队列Pop()Dequeue()当为空时返回 null)。那么这样写的代码将是线程安全的:

private WebRequestInfo Next()
{
    WebRequestInfo next = stack.PopOrNull()
    if (next == null)
    {
        next = queue.DequeueOrNull();
    }
    return next;
}
Run Code Online (Sandbox Code Playgroud)