Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.90/21: Рейтинг темы: голосов - 21, средняя оценка - 4.90
7 / 7 / 4
Регистрация: 25.03.2013
Сообщений: 117
.NET 4.x

Потокобезопасно изменить коллекцию

08.01.2014, 17:26. Показов 4673. Ответов 62
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Коллекция прибиндина (binding) к listbox-у на вьюшке. Данные из коллекции (статус) обновляются из интернета, что может происходить долго и для того, чтобы интерфейс не завис - все делаю в асинхронном методе. Проблема в том, что во время обновления юзверь может удалить или добавить в коллекцию items.
Попробывал заблочить клавиши "добавить" и "удалить" пока обновляется список, но беда - долго обновляться может а у юзверей нету терпения, и возможность удалять и добавлять в коллекцию данные во время ее обновления надо.
То как потокобезопасно изменять коллекцию?

Добавлено через 2 часа 30 минут
Есть предложения?) ТК я в тупике)
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
08.01.2014, 17:26
Ответы с готовыми решениями:

Изменить коллекцию в forEach
Задача: сделать uppercase всех слов, длина которых больше 3 символов. Как это сделать с помощью стрима? Мой набросок(значение элементов в...

Потокобезопасно ли одновременно добавлять в конец list обьекты и удалять из середины?
Добрый день. Потокобезопасно ли одновременно добавлять в конец list обьекты и удалять из середины? Есть два потока. Один парсит лист и...

Дано число R и коллекцию размера N. Преобразовать коллекцию, заменив все ее положительные элементы на число R
Всем доброго времени суток. Вот такая задачка. Дано число R и коллекция размера N. Преобразовать коллекцию, заменив все ее...

62
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
08.01.2014, 17:45
Держать 2 коллекции (или двже 3). По окончании загрузки данных с интернета (или в процессе, в зависимости от требований/возможностей) синхронизировать изменения с прибинденой коллекцией и присваивать ей результат объединения.
1
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
08.01.2014, 18:32
Создайте свою коллекцию и там управляйте потоками. Например так

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
public class MyList<T> : IEnumerable<T>
    {
        private readonly object _obj = new object();
        private readonly List<T> _ts = new List<T>();
 
        public int Count
        {
            get
            {
                lock (_obj)
                {
                    return _ts.Count;
                }
            }
        }
 
        public T this[int index]
        {
            get
            {
                lock (_obj)
                {
                    if (_ts.Count < index)
                        return _ts[index];
                    throw new IndexOutOfRangeException();
                }
            }
            set
            {
                lock (_obj)
                {
                    if (_ts.Count < index)
                        _ts[index] = value;
                    else
                        throw new IndexOutOfRangeException();
                }
            }
        }
 
        #region IEnumerable<T> Members
 
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            lock (_obj)
            {
                return new List<T>(_ts).GetEnumerator();
            }
        }
 
        public IEnumerator GetEnumerator()
        {
            return ((IEnumerable<T>) this).GetEnumerator();
        }
 
        #endregion
 
        public void Add(T item)
        {
            lock (_obj)
            {
                _ts.Add(item);
            }
        }
 
        public void Clear()
        {
            lock (_obj)
            {
                _ts.Clear();
            }
        }
 
        public bool Contains(T item)
        {
            lock (_obj)
            {
                return _ts.Contains(item);
            }
        }
 
 
        public bool Remove(T item)
        {
            lock (_obj)
            {
                return _ts.Remove(item);
            }
        }
 
        public int IndexOf(T item)
        {
            lock (_obj)
            {
                return _ts.IndexOf(item);
            }
        }
    }
1
7 / 7 / 4
Регистрация: 25.03.2013
Сообщений: 117
08.01.2014, 21:05  [ТС]
Создавать свою коллекцию - это очень фундаментальное дело))
Т.к. я юзаю async/await - потоками управлять не могу напрямую. А смешивать sync и async не хочется. Я сейчас обдумываю идею с 2-я коллекциями (хотя дорогое это удовольствие, но что поделаешь)
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
08.01.2014, 21:08
Цитата Сообщение от MisterMe Посмотреть сообщение
Я сейчас обдумываю идею с 2-я коллекциями
Как вы их будете синхронизировать? Вы начали синхронизацию, а пользователь нажал удалить?
1
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
08.01.2014, 22:11
Цитата Сообщение от Grishaco Посмотреть сообщение
Как вы их будете синхронизировать? Вы начали синхронизацию, а пользователь нажал удалить?
синхронизация в отличии от получения данных с сервера быстрая операция. пользователь может и подождать, а может даже и не заметит блокировки действия "удалить"
1
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
08.01.2014, 22:36
Цитата Сообщение от pycture Посмотреть сообщение
синхронизация в отличии от получения данных с сервера быстрая операция
Не спорю. Но этот гад (пользователь) обязательно так подгадает, что нажмет именно в то время, когда не нужно.
1
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
08.01.2014, 22:59
Как он нажмет удалить если на время синхронизации это действие заблокированно?
Цитата Сообщение от MisterMe Посмотреть сообщение
Попробывал заблочить клавиши "добавить" и "удалить" пока обновляется список.....
В данном случае синхронизируется.
1
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
08.01.2014, 23:32
pycture, я не претендую на оригинальность, но вот это

Цитата Сообщение от MisterMe Посмотреть сообщение
Попробывал заблочить клавиши "добавить" и "удалить" пока обновляется список
Чревато одной проблемой, при синхронизации возникнет ошибка, тогда кнопки на всегда останутся заблокированными. Как по мне лучше работа через блокировки, чем манипуляция контролами.
1
7 / 7 / 4
Регистрация: 25.03.2013
Сообщений: 117
08.01.2014, 23:58  [ТС]
Цитата Сообщение от Grishaco Посмотреть сообщение
pycture, я не претендую на оригинальность, но вот это

Чревато одной проблемой, при синхронизации возникнет ошибка, тогда кнопки на всегда останутся заблокированными. Как по мне лучше работа через блокировки, чем манипуляция контролами.
Полностью солидарен. Поэтому и создал тему.
На счет 2 коллекций:
пока 1 коллекция обновляеться (аля лезим в сеть и т.д.) - 2-ю коллекцию пользователь может менять как хочет.
А когда данные есть (после обновы) - обновить статус тех членов коллекции, которые имеют похожий ID. Думаю ссылку на строку перенести не так долго займет времени...+ синхронизировать ничего не надо. Это пока-что такая ИДЕЯ.
Мож я в чем-то ошибаюсь?
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
09.01.2014, 00:03
Цитата Сообщение от MisterMe Посмотреть сообщение
А когда данные есть (после обновы) - обновить статус тех членов коллекции, которые имеют похожий ID
Может попробовать просто сказать пользователю (т.е. заставить осознано нажать кнопку Обновить), что типа есть новые данные, а он уж пусть решает обновлять или нет. А то тут еще возникает проблема обновление списков, гридов, обновил в тихую, список прыгнул. В списке выделился другой элемент, пользователь не думая нажал Delete.
1
burning1ife
 Аватар для kenny69
1466 / 1287 / 294
Регистрация: 21.09.2008
Сообщений: 3,438
Записей в блоге: 9
09.01.2014, 00:58
Я вот если честно, не понисаю в чем проблема. А она, скорее всего, в неправильном проектировании.
Если вы используете async await, то вы можете возвращают значение из таких методов, а не менять коллекцию там же.
Получили значение через асинхронны метод, нашли элемент с таким id, если он есть обновили его значения, если нет, то ничего не делаем. А вообще сложно судить без кода.

Добавлено через 3 минуты
А если просто: не меняйте элементы коллекции в асинхронном потоке, а получайте данные асинхронно и присваивайте значения этому элементу, если его еще не удалили.
1
7 / 7 / 4
Регистрация: 25.03.2013
Сообщений: 117
09.01.2014, 01:31  [ТС]
kenny69, Спасибо! Правильно думать - смысл всей этой возни) Второй раз ставишь на путь истынный. Спасибо)
И в общем - ВСЕМ СПАСИБО за пищу для ума и поддержку)
0
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
09.01.2014, 07:39
Цитата Сообщение от Grishaco Посмотреть сообщение
pyctureЧревато одной проблемой, при синхронизации возникнет ошибка, тогда кнопки на всегда останутся заблокированными.
Для этого существует блок finally, в котором все элементы интерфейса можно вернуть во вменяемое состояние даже при наличии ошибок.
1
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
09.01.2014, 12:17
Цитата Сообщение от pycture Посмотреть сообщение
Для этого существует блок finally, в котором все элементы интерфейса можно вернуть во вменяемое состояние даже при наличии ошибок.
Если честно я пишу код вообще не используя блока try-catch-finally и людям запрещаю (если объект реализует IDisposable обязательная обертка в using). Все ошибки не предусмотришь, а приложение должно оставаться работоспособным не зависимо от возникших ошибок (не включая 3 необрабатываемых). Опять же это мой подход и никому его навязывать не собираюсь.
1
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
09.01.2014, 12:42
Цитата Сообщение от Grishaco Посмотреть сообщение
Если честно я пишу код вообще не используя блока try-catch-finally и людям запрещаю
То что вы не пользуетесь try-catch-finally это конечно ваше личное предпочтение, но запрещать людям пользоваться рекомендациями MSDN, это как-то... ну неправильно.
http://msdn.microsoft.com/ru-r... 00%29.aspx
Используйте "try-finally" и избегайте использования "try-catch" для игнорирования исключения. В хорошо написанном коде обработки исключения "try-finally" встречается намного чаще, чем "try-catch".

Целью оператора catch является обработка исключений (например, регистрация нефатальных ошибок). Целью оператора finally является выполнение кода независимо от того, было ли генерировано исключение. При размещении дорогих или ограниченных ресурсов, таких как соединения с базами данных или потоками, помещайте код в блок finally.
0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
09.01.2014, 12:49
Цитата Сообщение от pycture Посмотреть сообщение
но запрещать людям пользоваться рекомендациями MSDN
Во первых это не рекомендации, а статья об обработке исключений.
Во вторых, какой толк от finally в таком коде:

C#
1
2
3
4
5
6
7
8
9
try
{
int i = 0;
int j = 0;
int a = i/j;
}
finally
{
}
Начинающий просто напишет catch.

Но поверьте мне на слово, если человек начинает использовать try-catch в том месте, где не до конца разобрался с алгоритмом - это просто катастрофа, потом концов не найдешь, обработчик должен быть один (легче логировать), программист должен писать правильно код, а не так, вот тут периодически падает, но вроде ни на что не влияет, поставлю try.
0
09.01.2014, 13:02

Не по теме:

Цитата Сообщение от Grishaco Посмотреть сообщение
Во первых это не рекомендации
Да ошибся я немного. Это не рекомендации. Это правила. Раздел так и называется "Правила разработки исключений"
Цитата Сообщение от Grishaco Посмотреть сообщение
Во вторых, какой толк от finally в таком коде
Это какой-то клинический случай. Но в целом понятно, поросль воспитываете :)

0
438 / 362 / 100
Регистрация: 29.06.2010
Сообщений: 981
Записей в блоге: 1
09.01.2014, 13:09
Цитата Сообщение от pycture Посмотреть сообщение
Это какой-то клинический случай. Но в целом понятно, поросль воспитываете
Ну давайте начнем с того, что это то что первое взбрело в голову. Если хотите диалога, давайте поступим так я вам покажу свое видение, а вы мне свое.

Давайте для примера возьмем форму, на ней три текстбокса, первый x, второй y, третье результат x/y. И кнопка вычисления.

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

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        private static void Main()
        {
            Application.ThreadException += ApplicationThreadException;
            AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            try
            {
                Application.Run(new Form1());
            }
            catch (Exception exception)
            {
                CurrentDomainUnhandledException(null, new UnhandledExceptionEventArgs(exception, true));
            }
        }
 
        private static void ApplicationThreadException(object sender, ThreadExceptionEventArgs e)
        {
            CurrentDomainUnhandledException(sender, new UnhandledExceptionEventArgs(e.Exception, true));
        }
 
        private static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            var exceptionObject = e.ExceptionObject as Exception;
            if (exceptionObject != null) MessageBox.Show(exceptionObject.Message);
        }
    }
 
    public partial class Form1 : Form
    {
        private Button button1;
        private TextBox textBox1;
        private TextBox textBox2;
        private TextBox textBox3;
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            int x;
            if (!int.TryParse(textBox1.Text, out x))
            {
                throw new Exception("Некорретное значение х");
            }
 
            int y;
            if (!int.TryParse(textBox2.Text, out y))
            {
                throw new Exception("Некорретное значение y");
            }
 
            textBox3.Text = (x/y).ToString();
        }
 
        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            button1 = new Button();
            textBox1 = new TextBox();
            textBox2 = new TextBox();
            textBox3 = new TextBox();
            SuspendLayout();
            // 
            // button1
            // 
            button1.Location = new Point(37, 90);
            button1.Name = "button1";
            button1.Size = new Size(75, 23);
            button1.TabIndex = 0;
            button1.Text = "button1";
            button1.UseVisualStyleBackColor = true;
            button1.Click += button1_Click;
            // 
            // textBox1
            // 
            textBox1.Location = new Point(12, 12);
            textBox1.Name = "textBox1";
            textBox1.Size = new Size(100, 20);
            textBox1.TabIndex = 1;
            // 
            // textBox2
            // 
            textBox2.Location = new Point(12, 38);
            textBox2.Name = "textBox2";
            textBox2.Size = new Size(100, 20);
            textBox2.TabIndex = 2;
            // 
            // textBox3
            // 
            textBox3.Location = new Point(12, 64);
            textBox3.Name = "textBox3";
            textBox3.Size = new Size(100, 20);
            textBox3.TabIndex = 2;
            // 
            // Form1
            // 
            AutoScaleDimensions = new SizeF(6F, 13F);
            AutoScaleMode = AutoScaleMode.Font;
            ClientSize = new Size(216, 123);
            Controls.Add(textBox3);
            Controls.Add(textBox2);
            Controls.Add(textBox1);
            Controls.Add(button1);
            Name = "Form1";
            Text = "Form1";
            ResumeLayout(false);
            PerformLayout();
        }
    }
При этом прошу заметить этот код будет работать при любом косяке поросли.
0
1195 / 588 / 88
Регистрация: 20.09.2012
Сообщений: 1,881
09.01.2014, 14:23
Можно конечно и так. Хотя логгирование кривых значений начальных данных, да еще и через исключения - это точно не моё. Теперь по коду. Логика обработки значений не всегда такая простая и тем более пользователь может быть вообще без понятия, что у него там чтото на чтото делится. В результате выскакивающий из табакерки "Деление на ноль" ничего ему не говорит (пользователей читающих документацию я еще ни разу не видел), и как правило заканчивается воплями "ниче не работает", а в клинических случаях разбором полетов с программерами (и такое бывает). Если же воспользоваться ненавистным вам catch, то можно безымянный DivideByZeroException перевести в вполне осознанное сообщение для пользователя
C#
1
2
3
4
5
6
7
8
9
10
11
try
{
    int a = 1;
    int b = 0;
    Console.WriteLine("{0}", a / b);
}
catch (DivideByZeroException _)
{
    Console.WriteLine("При положении Луны в Стрельце, значение не может быть вычислено. Введите другое значение b");
    throw;
}
Пользователь теперь знает, что он сам дурак и, и что важно, он знает как ему самостоятельно исправить данную ошибку. В лог же упадет все, что и в вашем варианте.

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

А теперь можно посмотреть на другой специфичный случай. Есть коллекция (неважно какая), ее нужно преобразовать в другую (загрузить файлы если это имена файлов, чтото сложное посчитать, собрать данные с 10 веб-сервисов и т.д.), всю. Если элемент нельзя загрузить/посчитать ему должно быть присвоено значение по умолчанию. Процедура загрузки/расчета каждого отдельного элемента может упасть по любой причине с исключением. Вопрос: как без try catch добится получения коллекции?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
09.01.2014, 14:23
Помогаю со студенческими работами здесь

Отобразить коллекцию
Возник следующий вопрос: Некоторым образом формируется коллекция документов. Хотелось бы всю эту коллекцию выводить во вью в...

Реализовать коллекцию
Задание. Создать класс Student с двумя полями и конструктором с параметрами. Если нужно добавить в класс дополнительные методы или...

Отсортировать коллекцию
Нужно отсортировать объем двигателя (FUELCONSUMPTION ) по возрастающей public class Bentley extends AbstractCar { private...

Заполнить коллекцию
Создать коллекцию для пар Student, int. Создать метод который будет добавлять в коллекцию пару Student, int. Целое число должно быть...

Объект в коллекцию
Хочу, чтобы объекты которые я создаю (Person person1 = new Person), каждый при создании, автоматически ложился в List и я мог вывести на...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru