Научно-образовательный IT-форум при КНИТУ-КАИ

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Научно-образовательный IT-форум при КНИТУ-КАИ » Задачи и вопросы » [+] Как устроен ConcurrentBag в .Net?


[+] Как устроен ConcurrentBag в .Net?

Сообщений 1 страница 6 из 6

1

Ранее мне попалась очень интересная статья [ссылка] на эту тему. Но меня озадачил один момент. Почему, если количество элементов в коллекции более двух, то взятие (Take) без блокировки допустимо? При этом ясно, что, когда мы добавляем (Add) элемент в коллекцию, то текущий экземпляр коллекции требуется заблокировать, если число элементов в коллекции меньше двух, так как в этот момент один из потоков может забирать элемент. Но почему же нельзя забирать без блокировки списка при наличии двух элементов в экземпляре коллекции, учитывая что взятия осуществляется с конца списка, для меня осталось загадкой.

https://bitbucket.org/landwatersun/forum/downloads/201803011250.png

А если быть точным, то в статье смутил такой фрагмент:

... если в связном списке более двух элементов, то поток может «своровать» элемент без блокировки всего листа. То есть в таком случае невозможно «состояние гонки», так как между добавляемым и забираемым элементом есть как минимум один промежуточный.

На основании данного фрагмента можно понять, что три элемента списка: добавляемый, имеющийся, забираемый. Но ведь, если не учитывать слово «добавляемый», то в списке в качестве исходных данных находятся только два элемента. Почему сделан акцент на «если в связном списке более двух элементов», не ясно.

2

Если нет элемента в списке, который можно извлечь, то метод Take() будет ожидать пока он не появится. Метод Add() работает аналогичным способом, но по отношению к добавлению элемента: метод будет ожидать пока не появиться возможность добавить элемент в список. Если в коллекции меньше двух элементов, то метод Add() вызовет метод блокировки связного списка FreezeBag на время добавления элемента и обновления ссылок списков. Если блокировки не будет на время добавления элемента, если в списке 2 элемента или менее, то ссылки могут обновиться не корректно, что нарушит работу списков.

Отредактировано Abramov_S. (2018-03-25 22:15:57)

3

Спасибо за комментарий, но все сказанное не вызывает сомнений и в статье. Основное внимание нужно уделить к взятию (Take) элемента из списка. У меня есть предложение по ответу, позднее опубликую. Но так или иначе новые комментарии приветствуются.

4

Нельзя выполнять операцию take когда два элемента в списке потому что
поток владелец коллекции берет элементы с головы,а поток который ворует берет с хвоста ,и получается возникает условие гонки когда поток владелец записывает в переменную m_head и m_tail 2 элемент,а поток который ворует записывает m_head и m_tail как  1 элемент коллекции ,поэтому нужно промежуточное значение

ссылка на подтверждение что поток владелец берет с головы
This is where it gets tricky. If the current thread’s list has items in it, then it peeks or removes the head item (not the tail item) from the local list and returns that.

Ссылка

Исходники

Отредактировано Rail Khisamutdinov (2018-03-26 22:36:24)

5

Мне кажется в исходной статье допущена ошибка (см. подзаголовок "Получение элемента из коллекции"):

Причем он должен «своровать» элемент, не перепутав и не помешав потоку владельцу правильно ДОБАВЛЯТЬ (правильно => ЗАБИРАТЬ) элемент.


Как Вы считаете, Rail Khisamutdinov? Потому как, при "воровстве" элемента соседним потоком, текущему потоку ничто не мешает добавлять элемент при наличии в списке более одного элемента.

6

согласен,если мы даже откроем исходники в методе добавления необходимое условие для синхронизации во избежание конфликтов с ворующими потоками <2 ,то есть когда два элемента ,добавлять уже можно


Вы здесь » Научно-образовательный IT-форум при КНИТУ-КАИ » Задачи и вопросы » [+] Как устроен ConcurrentBag в .Net?