0

このコードが安全でない理由がわかりません。安全ではないことを証明するテストケースがあります。

        List<T> _l = new List<T>();
        public void Add(T t)
        {
            lock (_l)
            {
                _l.Add(t);
                Monitor.PulseAll(_l);
            }
        }
        public T[] RemoveToArray(TimeSpan timeout)
        {
            lock (_l)
            {
                if (_l.Count == 0)
                {
                    bool timedout = !Monitor.Wait(_l, timeout);

                    // no lock 
                    if (timedout)
                    {
                        return new T[0];
                    }
                }
                // with lock
                T[] items = _l.ToArray();
                _l.Clear();
                return items;
            }
        }

この関数は、新しいアイテムが到着するまで、ある程度の時間 (その後タイムアウト) 待機することになっています。時間切れの場合は空の配列を返し、それ以外の場合は内部リストのすべての要素を配列に排出します。テスト コードでは、追加するタスクと削除するタスクの 2 つのタスクを作成しました。

        times = 3;
        Task[] tasks = new Task[2];
        tasks[0] = Task.Factory.StartNew(() =>
        {
            firstRemoveItems = _l.RemoveToArray(_infinite);
            Util.Delay(TimeSpan.FromMilliseconds(10)).Wait();
            secondRemoveItems = _l.RemoveToArray(_infinite);
        });
        tasks[1] = Task.Factory.StartNew(() =>
        {
            _l.Add(new object());
            Util.Delay(TimeSpan.FromMilliseconds(5)).Wait();
            for (int i = 1; i < times; i++)                
                _l.Add(new object());
        });

アイテムが 3 つ追加されましたが、合計アイテム数は 2、3、4 でした。何が問題なのかよくわかりません。待機タイムアウト後にロックが再取得されると思いますか?

4

0 に答える 0