27

ロックステートメントにyieldreturnがある場合、各yieldでロックが解除されますか(以下の例では5回)、またはリスト内のすべてのアイテムに対して1回だけロックが解除されますか?

ありがとう

    private List<string> _data = new List<string>(){"1","2","3","4","5"};
    private object _locker =new object();
    public IEnumerable<string> GetData()
    {
        lock (_locker)
        {
            foreach (string s in _data)
            {
                yield return s;
            }
        }
    }
4

3 に答える 3

9

編集: この回答は間違っていましたが、正しいとマークされているため削除できません。正解については、以下の @Lockszmith の回答を参照してください。

言い換え:

yieldが返されるたびにロックが解除されることはありません。注: ただし、列挙子が完了すると、つまり foreach ループが終了すると解放されます。

編集を終了

元の回答 (間違っています):

あなたのシナリオでは、ロックは一度だけ取得されます。つまり、一度だけです。ただし、共有リソースは扱っていません。以下のコンソール アプリのように共有リソースを処理し始めると、いくつかの興味深いことが起こります。

結果から、各 yield でロックが一時的に解放されることがわかります。また、リスト 1 のロックは、すべての項目がコンソールに書き込まれるまで解放されないことに注意してください。これは、GetData() メソッドがループの反復ごとに部分的に実行され、ループの反復ごとにロックを一時的に解放する必要があることを示しています。利回り宣言。

    static void Main(string[] args)
    {
        object locker = new object();
        IEnumerable<string> myList1 = new DataGetter().GetData(locker, "List 1");
        IEnumerable<string> myList2 = new DataGetter().GetData(locker, "List 2");
        Console.WriteLine("start Getdata");
        foreach (var x in myList1)
        {
            Console.WriteLine("List 1 {0}", x);
            foreach(var y in myList2)
            {
                Console.WriteLine("List 2 {0}", y);
            }
        }
        Console.WriteLine("end GetData");
        Console.ReadLine();
    }

    public class DataGetter
    {
        private List<string> _data = new List<string>() { "1", "2", "3", "4", "5" };

        public IEnumerable<string> GetData(object lockObj, string listName)
        {
            Console.WriteLine("{0} Starts", listName);
            lock (lockObj)
            {
                Console.WriteLine("{0} Lock Taken", listName);
                foreach (string s in _data)
                {
                    yield return s;
                }
            }
            Console.WriteLine("{0} Lock Released", listName);
        }
    }
}

結果:

            start Getdata
            List 1 Starts
            List 1 Lock Taken
            List 1 1
            List 2 Starts
            List 2 Lock Taken
            List 2 1
            List 2 2
            List 2 3
            List 2 4
            List 2 5
            List 2 Lock Released
            List 1 2
            List 2 Starts
            List 2 Lock Taken
            List 2 1
            List 2 2
            List 2 3
            List 2 4
            List 2 5
            List 2 Lock Released
            List 1 3
            List 2 Starts
            List 2 Lock Taken
            List 2 1
            List 2 2
            List 2 3
            List 2 4
            List 2 5
            List 2 Lock Released
            List 1 4
            List 2 Starts
            List 2 Lock Taken
            List 2 1
            List 2 2
            List 2 3
            List 2 4
            List 2 5
            List 2 Lock Released
            List 1 5
            List 2 Starts
            List 2 Lock Taken
            List 2 1
            List 2 2
            List 2 3
            List 2 4
            List 2 5
            List 2 Lock Released
            List 1 Lock Released
            end GetData

しかし、ここで彼が本当に素晴らしいのは結果です。「start GetData」という行は、DataGetter().GetData() の呼び出しの後、GetData() メソッド内で発生するすべての前に発生することに注意してください。これは遅延実行と呼ばれ、yield return ステートメントの美しさと有用性を示しています。外側のループ内のどこでもループから抜け出すことができ、内側のループへの呼び出しはもうありません。これは、必要がなければ内側のループ全体を反復する必要がないことを意味し、外側のループに早く結果を取得し始めることも意味します。

于 2010-05-17T08:46:44.467 に答える