приведите к возвратам в операторе блокировки

если у меня есть возврат урожая в операторе блокировки, блокировка становится вынутой на каждом урожае (5 раз в примере ниже) или только однажды для всех объектов в списке?

Спасибо

    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;
            }
        }
    }
21
задан Daniel Dyson 17 May 2010 в 10:04
поделиться

1 ответ

Редактировать: Этот ответ был неправильным, но я не могу удалить его, так как он был отмечен как правильный. Пожалуйста, смотрите ответ @Lockszmith ниже для правильного ответа.

Перефразировано:

Блокировка НИКОГДА не снимается между каждым возвратом дрозда. ПРИМЕЧАНИЕ: Однако она освобождается, когда перечислитель завершает работу, т.е. когда цикл foreach заканчивается.

Конец редактирования

Оригинальный ответ (неверный):

В вашем сценарии блокировка будет снята только один раз. Короче говоря, только один раз. Однако вы не имеете дело с общими ресурсами. Когда вы начинаете работать с общими ресурсами, как в приведенном ниже консольном приложении, происходят интересные вещи.

Из результатов видно, что блокировка временно снимается на каждом выходе. Также обратите внимание, что блокировка списка 1 не снимается до тех пор, пока все элементы не будут записаны в консоль, что свидетельствует о том, что метод GetData() выполняется частично на каждой итерации цикла и что блокировка должна временно сниматься при каждом операторе yield.

    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: В любом месте вашего внешнего цикла вы можете выйти из цикла, и вызовов внутреннего цикла больше не будет. Это означает, что вам не придется выполнять итерации всего внутреннего цикла, если в этом нет необходимости, а также то, что вы начнете получать результаты во внешнем цикле раньше.

8
ответ дан 29 November 2019 в 20:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: