【问题标题】:How to unit test a thread safe queue如何对线程安全队列进行单元测试
【发布时间】:2013-05-08 20:04:50
【问题描述】:

我需要一个具有这些要求的简单数据结构:

  • 它的行为应该像一个队列,
  • 所有入队操作都应该是原子的。

我在多线程方面的经验非常有限,但这就是我的想法:

public class Tickets
{
    private ConcurrentQueue<uint> _tickets;

    public Tickets(uint from, uint to)
    {
        Initialize(from, to);
    }

    private readonly object _lock = new object();
    public void Initialize(uint from, uint to)
    {
        lock(_lock)
        {
            _tickets = new ConcurrentQueue<uint>();

            for (uint i = from; i <= to; i++)
            {
                _tickets.Enqueue(i);
            }
        }
    }

    public uint Dequeue()
    {
        uint number;
        if (_tickets.TryDequeue(out number))
        {
            return number;
        }

        throw new ArgumentException("Ticket queue empty!");
    }
}

第一个问题:这段代码可以吗?

第二个问题:我如何对这个类进行单元测试(例如,两个线程定期在队列上执行出队操作,元素为(1、2、3、4、5、6),第一个线程应该只得到奇数和第二个线程只有偶数)?我试过这个,但断言没有执行:

[Test]
public void Test()
{
    var tickets = new Tickets(1, 4);
    var t1 = new Thread(() =>
                            {
                                Assert.AreEqual(1, tickets.Dequeue());
                                Thread.Sleep(100);
                                Assert.AreEqual(3, tickets.Dequeue());
                            });


    var t2 = new Thread(() =>
                            {
                                Assert.AreEqual(2, tickets.Dequeue());
                                Thread.Sleep(100);
                                Assert.AreEqual(4, tickets.Dequeue());
                            });

    t1.Start();
    t2.Start();
}

【问题讨论】:

  • 第一个问题的答案:你的集合不是线程安全的,因为Dequeue 可以在Initializing 时调用。
  • 需要锁定您的Dequeue。同样,两个线程将像这样理想地交错的概念也是有缺陷的。不能保证他们会像那样轮流使用它,当然不是在您提供的代码中。
  • @weston:我是这么认为的,这就是为什么我问如何以适当的方式进行单元测试。
  • 您不使用框架并发队列是否有原因? msdn.microsoft.com/en-us/library/…
  • 他们以“循环”的方式从队列中取出重要还是只是为了测试目的。即在真实环境中,您是否关心线程 1 是否在线程 2 之前同时使用 1 和 2?

标签: c# .net multithreading unit-testing queue


【解决方案1】:

多线程和单元测试的问题是时间问题之一。当您尝试将多个线程引入单元测试时,您会面临无法重现的测试结果的风险,即测试有时会通过但有时不会通过。

但为了解释为什么您的断言可能未执行,单元测试在线程之前完成。它需要等待线程完成,而不是仅仅将它们踢掉并继续前进。单元测试框架本身不是线程安全的或者不能从其他线程调用 Asserts 也是可行的。

对不起,这不是一个解决方案,但我也不知道有任何多线程代码的自动化测试解决方案。

另请参阅:How should I unit test threaded code?

【讨论】:

    【解决方案2】:

    我会使用国际象棋:http://research.microsoft.com/en-us/projects/chess

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-01
      • 2018-08-15
      • 2010-09-17
      • 2019-01-01
      • 2020-04-09
      相关资源
      最近更新 更多