Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.53/15: Рейтинг темы: голосов - 15, средняя оценка - 4.53
63 / 64 / 44
Регистрация: 05.12.2014
Сообщений: 475
1

Обезопасить доступ к коллекции из разных потоков

02.12.2016, 12:52. Показов 3114. Ответов 37
Метки нет (Все метки)

станет ли безопасным метод AddSafe?
C#
1
2
3
4
5
6
7
8
9
10
11
12
public static MyCollection myCol = new MyCollection();
 
class MyCollection: ObservableCollection<string>
{
    public void AddSafe(string item)
    {
        lock(this)
        {
            this.Add(item);
        }
    }
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
02.12.2016, 12:52
Ответы с готовыми решениями:

Заполнение коллекции из разных потоков
Добрый день. Что я могу использовать вместо удобной ObservableCollection&lt;T&gt;, если мне надо...

Одновременный доступ к коллекции из двух потоков
Здравствуйте. В программе открываю UDP-сокет, в который приходят данные с устройства. Вкратце, у...

Доступ к БД с разных потоков
как реализовать доступ к одной базе данных с разных потоков? когда один сервер обрабатывает...

Доступ к очереди из разных потоков
Подскажите по многопоточности, у меня есть очередь (Queue) и мне надо организовать к ней доступ из...

37
Эксперт .NET
14877 / 11263 / 2951
Регистрация: 17.09.2011
Сообщений: 18,863
02.12.2016, 14:38 2
Цитата Сообщение от Jotun Посмотреть сообщение
станет ли безопасным метод AddSafe?
Да, только не используйте lock (this). Лучше создайте закрытый readonly-объект и замыкайтесь на нем.
Ну и учтите, что у вас замыкание будет держаться до тех пор, пока не отработают все подписчики на события.
1
63 / 64 / 44
Регистрация: 05.12.2014
Сообщений: 475
04.12.2016, 11:59  [ТС] 3
Но всё равно это похоже не выход. Если я хочу только изменить конкретный объект в коллекции - то нужен будет lock
0
Эксперт .NET
14877 / 11263 / 2951
Регистрация: 17.09.2011
Сообщений: 18,863
04.12.2016, 21:22 4
Цитата Сообщение от Jotun Посмотреть сообщение
Но всё равно это похоже не выход.
Что именно?
0
63 / 64 / 44
Регистрация: 05.12.2014
Сообщений: 475
04.12.2016, 22:49  [ТС] 5
Цитата Сообщение от kolorotur Посмотреть сообщение
Что именно?
да, непонятно написал

Просто хотел уменьшить количество локов разбросанных по коду и собрать их внутри коллекции.
0
137 / 137 / 53
Регистрация: 14.06.2016
Сообщений: 467
05.12.2016, 06:25 6
Цитата Сообщение от Jotun Посмотреть сообщение
Просто хотел уменьшить количество локов разбросанных по коду и собрать их внутри коллекции.
Ну так собери. Вот пример реализации http://theburningmonk.com/2010... in-csharp/
Правда у меня в релизном проекте всё равно довольно часто бросалось исключение (коллекция изменена), хз почему.
0
Эксперт .NET
8863 / 6173 / 1030
Регистрация: 21.01.2016
Сообщений: 23,336
05.12.2016, 07:06 7
Цитата Сообщение от Jotun Посмотреть сообщение
Просто хотел уменьшить количество локов разбросанных по коду и собрать их внутри коллекции.
Мало того, что эти локи и должны быть в одном месте, так ещё можно обойтись и без локов, если коллекция только читается: ReaderWriterLockSlim.
0
483 / 396 / 68
Регистрация: 14.02.2014
Сообщений: 1,930
05.12.2016, 10:30 8
Jotun, А может сразу BlockingCollection использовать?
0
63 / 64 / 44
Регистрация: 05.12.2014
Сообщений: 475
05.12.2016, 11:19  [ТС] 9
Цитата Сообщение от aquaMakc Посмотреть сообщение
otun, А может сразу BlockingCollection использовать?
Я бы с удовольствием но нужно выводить данные в элементы ui
0
483 / 396 / 68
Регистрация: 14.02.2014
Сообщений: 1,930
05.12.2016, 11:21 10
Jotun, используй для этого отдельный класс-обёртку данных. И формируй коллекцию обёрток на основе коллекции данных (LINQ`ом это вообще элементарно делается).
0
63 / 64 / 44
Регистрация: 05.12.2014
Сообщений: 475
31.07.2017, 22:47  [ТС] 11
Может кто-то рассказать о BindingOperations.EnableCollectionSynchronization - https://msdn.microsoft.com/en-... .110).aspx

Если я правильно понял, то достаточно вызвать данный метод для коллекции и можно не парится с локами?
0
Эксперт .NET
14877 / 11263 / 2951
Регистрация: 17.09.2011
Сообщений: 18,863
01.08.2017, 11:01 12
Цитата Сообщение от Jotun Посмотреть сообщение
Если я правильно понял, то достаточно вызвать данный метод для коллекции и можно не парится с локами?
Нет, данный метод всего лишь предоставляет системе привязки объект для синхронизации доступа к коллекции, поскольку вы не можете лочить ее сами.
Во всех остальных многопоточных случаях коллекцию все равно придется лочить. И если вы пользуетесь данным методом, то лучше лочить ее на тот же объект, ссылка на который была передана вторым аргументом в EnableCollectionSynchronization.
1
63 / 64 / 44
Регистрация: 05.12.2014
Сообщений: 475
01.08.2017, 18:33  [ТС] 13
Цитата Сообщение от kolorotur Посмотреть сообщение
Нет, данный метод всего лишь предоставляет системе привязки объект для синхронизации доступа к коллекции, поскольку вы не можете лочить ее сами.
То есть если у меня есть коллекция привязанная к элементу интерфейса, и котороя может изменятся в другом потоке, то нужно вызывать этот метод чтобы всё было нормально?
0
Эксперт .NET
14877 / 11263 / 2951
Регистрация: 17.09.2011
Сообщений: 18,863
01.08.2017, 18:35 14
Цитата Сообщение от Jotun Посмотреть сообщение
То есть если у меня есть коллекция привязанная к элементу интерфейса, и котороя может изменятся в другом потоке, то нужно вызывать этот метод чтобы всё было нормално?
Вызвать этот метод достаточно один раз.
Но в отдельном потоке надо будет лочить коллекцию при ее изменении.
0
63 / 64 / 44
Регистрация: 05.12.2014
Сообщений: 475
01.08.2017, 19:27  [ТС] 15
Цитата Сообщение от kolorotur Посмотреть сообщение
Вызвать этот метод достаточно один раз.
Да, я понял, просто сам принцип пытаюсь понять
0
Эксперт .NET
14877 / 11263 / 2951
Регистрация: 17.09.2011
Сообщений: 18,863
02.08.2017, 10:04 16
Цитата Сообщение от Jotun Посмотреть сообщение
сам принцип пытаюсь понять
При доступе к коллекции из разных потоков необходимо этот доступ синхронизировать, если коллекция не является потокобезопасной.

Если коллекцией пользуетесь только вы, то все просто: достаточно определить критические зоны, в которых производится работа с коллекцией, проще всего это делается конструкцией lock.

Все становится малость сложнее, когда этой же коллекцией начинает пользоваться код, реализующий отрисовку пользовательского интерфейса, то есть "кишки" WPF.

Здесь у вас практически нет никакого контроля над тем, когда будет произведена переотрисовка интерфейса и как следствие будет произведен доступ к коллекции из внутренностей WPF. Получается, что вся синхронизация доступа сразу теряет смысл, т.к. она работает только тогда, когда доступ к общему ресурсу синхронизирован везде, а не где-либо выборочно.

Метод EnableCollectionSynchronization фактически просто передает во внутренности фреймворка ссылку на объект, на котором WPF будет замыкаться каждый раз при работе с вашей коллекцией, потому и передавать туда нужно ту же ссылку, которую вы используете для замыкания при работе с коллекцией в ваших потоках.

Дополнительно этот метод включает маршаллинг обработки событий коллекции в GUI-поток.

Никакой магии.
1
63 / 64 / 44
Регистрация: 05.12.2014
Сообщений: 475
07.08.2017, 15:20  [ТС] 17
Что-то не получается у меня нифига.
Сделал вот такую коллекцию:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    public class AutoSkillUseCollection : ObservableCollection<AutoSkillListItem>
    {
        private object _lock = new object();
 
        public void AddSafe(AutoSkillListItem item)
        {
            lock (_lock)
                this.Add(item);
        }
 
        public void RemoveSafe(AutoSkillListItem item)
        {
            lock (_lock)
                this.Remove(item);
        }
 
        public void TryToLaunchSelfHeal()
        {
            lock (_lock)
                foreach (AutoSkillListItem item in this)
                    if (item.SkillType == AutoSkillTypes.SelfHeal)
                        (item as SelfHealListItem).TryToLaunch();
        }
 
        // куча подобных функций залоченых _lock
}
Переодически прога зависает при нажатии на кнопку Add или кнопку с крестиком. Пауза вижуал студии показывает на _lock в методах AddSafe или RemoveSafe соответственно. Методы коллекции (кроме AddSafe и RemoveSafe) могут вызываться из другого потока. Почему оно виснет а не дожидается отпуска лока не понимаю
0
Миниатюры
Обезопасить доступ к коллекции из разных потоков  
Эксперт .NET
14877 / 11263 / 2951
Регистрация: 17.09.2011
Сообщений: 18,863
07.08.2017, 16:02 18
Цитата Сообщение от Jotun Посмотреть сообщение
куча подобных функций залоченых _lock
Наверное, где-то в этой куче что-то делается не так.
Метод EnableCollectionSynchronization был вызван? Если да, то какая ссылка была в него передана в качестве объекта для синхронизации?
Интересно так же что делается в методе TryToLaunch класса SelfHealListItem.

Похоже, у вас где-то конфликт замыканий и приложение виснет наглухо.
0
63 / 64 / 44
Регистрация: 05.12.2014
Сообщений: 475
07.08.2017, 16:34  [ТС] 19
Цитата Сообщение от kolorotur Посмотреть сообщение
Метод EnableCollectionSynchronization был вызван? Если да, то какая ссылка была в него передана в качестве объекта для синхронизации?
Сначала нет, попробовал передать туда этот _lock сделав его public но не проканало.
Цитата Сообщение от kolorotur Посмотреть сообщение
нтересно так же что делается в методе TryToLaunch класса SelfHealListItem.
да там много чего делается, я даже не знаю как стороннему человеку понять что-то в уже большой программе....
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
        public void TryToLaunch(string name)
        {
            if (!IsEnabled) return;
            if (!IsReady) return;
            if (NameList.Count < 1 || Guids.Count < 1) return;
            if (!NameList.ContainsCheckedName(name)) return;
 
            Guid guid;
            if (Guids.ContainsKey(name))
                guid = Guids[name];
            else
                return;
            
            if (Vars.RequestList.ContainsGuid(guid)) return;
            
            L2PartyMember pm;
            pm = Vars.PartyList.GetItemByName(name);
            if (pm == null) return;
            if (!Vars.CreaturesList.ContainsObjectID(pm.objId)) return;
            
            int max = 0, val = 0;
 
            switch (HealType)
            {
                case HealTypes.HP: max = pm.MaxHP; val = pm.HP; break;
                case HealTypes.MP: max = pm.MaxMP; val = pm.MP; break;
                case HealTypes.CP: max = pm.maxCP; val = pm.CP; break;
            }
            if (max == 0) return;
            int curPercents = val * 100 / max;
            if (curPercents <= Percents)
            {
                Request request = new Request(guid, MotherRequestType.Heal, IsNeedTarget, pm, false, Skill, Send.RequestMagicSkillUse(Skill.id, false));
                Vars.RequestList.AddSafe(request);
            }
            else
                TryToStop(name);
        }
0
Эксперт .NET
14877 / 11263 / 2951
Регистрация: 17.09.2011
Сообщений: 18,863
07.08.2017, 17:36 20
Цитата Сообщение от Jotun Посмотреть сообщение
я даже не знаю как стороннему человеку понять что-то в уже большой программе
В основном высматриваю запуск каких-нибудь потоков или, не дай бог, асинхронные вызовы вперемешку с замыканиями.
Где-нибудь в вашем коде производится подписка на события этой коллекции?
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
07.08.2017, 17:36

Заказываю контрольные, курсовые, дипломные работы и диссертации здесь.

Доступ к стриму из разных потоков
Задача такая, имеем мемористрим, в одном потоке постоянно пишем его. В другом потоке необходимо по...

Доступ к функции с разных потоков C++ Builder
Как правильно объявить/создать функцию в C++Builder, чтобы она была доступна со всех потоков,...

Обеспечить корректный доступ к элементу из разных потоков
Возникла такая проблема. Есть приложение и в приложение есть элемент, к которому прикреплён некий...

Доступ к файлам из разных потоков, как исключить коллизии?
Разные потоки осуществляют чтение разных файлов произвольным образом командой...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.