7 / 4 / 3
Регистрация: 07.08.2016
Сообщений: 65
|
||||||
1 | ||||||
.NET 4.x Отслеживание изменений массива данных из второго потока18.01.2019, 19:37. Показов 4565. Ответов 49
Метки многопоточность (Все метки)
Хочу узнать мнения гуру касаемо подхода в реализации следующего. Есть массив данных и два потока. Один поток производит операции с элементами этого массива (добавление и обновление рандомных элементов). Другой поток должен отслеживать изменения в этом массиве и строго дублировать его. Первый поток должен быть полностью автономным и не зависеть от работы второго. Т.е работа второго никаким образом не должна тормозить работу первого, обратное же допустимо. Т.к. сам массив может быть очень большим(а в теории бесконечным), то проходить циклом во втором потоке весь массив и искать изменения не совсем разумно. Получается первый поток должен сообщить второму о том, какие элементы он изменил (добавил/обновил).
У меня получилось вот это:
После того как Reader прочитал все изменения, выставляем isRead в true. Первый поток увидев, что изменения были считаны перед добавлением в _MultiThread.data затирает все с помощью _clear(). И вроде все работает как надо. Но, так как я в многопоточности новичок, хотел бы знать как можно иначе реализовать алгоритм? Возможно ли использовать lock и обойтись без ManualResetEventSlim ? И есть ли в моей реализации ошибки?
0
|
18.01.2019, 19:37 | |
Ответы с готовыми решениями:
49
Отслеживание изменений БД Отслеживание изменений Отслеживание изменений в БД Отслеживание изменений |
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
|
|
21.01.2019, 21:40 | 41 |
Ну в было элементе битового массива (который состоит из байт в конкретном случае) значение, например, 128. Первый поток поменял массив данных и теперь должен в массиве бит изменить число 128 на число 130. Для этого он сначала считывает число 128 из этого массива в регистр. Сразу после этого второй поток тоже считывает оттуда же число 128, просматривает все его биты и уже собирается записать в массив 0 вместо 128, как его опережает первый поток, который записывает значение 130. После этого второй поток сразу же записывает значение 0 вместо 130. То есть бит, установленный первым потоком никогда не будет прочитан вторым. Вот я об этом говорил. И оперирование общей для потоков памяти идёт байтами, а не битами. А вы мне пишете:
1
|
7 / 4 / 3
Регистрация: 07.08.2016
Сообщений: 65
|
|
21.01.2019, 22:03 [ТС] | 42 |
Ага, дошло. Спасибо.
Тогда можно ли как-то блокировать определенный байт ? Вместо блокировки всего массива байтов? Добавлено через 12 минут volatile здесь как то нужен?
0
|
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
|
|||||||||||
21.01.2019, 22:08 | 43 | ||||||||||
Нет. И наверное лучше не в байтах хранить, а в long-ах. Вот такая конструкция часто используется для обновления.
volatile не позволяет компилятору/процессору переупорядочивать инструкции определённым образом. Например тут
1
|
7 / 4 / 3
Регистрация: 07.08.2016
Сообщений: 65
|
|
21.01.2019, 22:40 [ТС] | 44 |
Как я понял, там сравниваются значения до и после?
А если оставить байты и просто сообщать второму потоку в каком именно байте в данный момент времени копошится первый поток, а перед тем как обнулить бит проверять не находится ли первый поток в том же байте? Если находится, то прочитать текущий байт побитно заново.
0
|
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
|
|
21.01.2019, 22:43 | 45 |
Ну да, там проверяется, что в массиве значение не изменилось, пока поток вычислял новое.
Между проверкой и записью может пройти сколько угодно времени, и к этому моменту результаты проверки могут стать не актуальными.
1
|
7 / 4 / 3
Регистрация: 07.08.2016
Сообщений: 65
|
|
22.01.2019, 00:27 [ТС] | 46 |
Тогда остается вариант считывания байта во временную переменную, его побитовое изменение и перед обратной записью в массив сверка предыдущего значения с текущим в массиве через Interlocked.CompareExchange ?
Interlocked.CompareExchange получается блокирует элемент массива или чаво? Добавлено через 1 час 5 минут Почему то byte быстрее работают
0
|
Модератор
|
|
22.01.2019, 00:41 | 47 |
Это зависит от процессора в большинстве случаев целочисленные операции (в том числе логические) быстрее всего работаю с int и uint. Но надо проверять на конкретном процессоре.
Добавлено через 1 минуту Если Вам нужны именно биты, то лучше всего их хранить как bool. Иначе компилятор C# может вставлять ненужные приведения типов.
0
|
7 / 4 / 3
Регистрация: 07.08.2016
Сообщений: 65
|
||||||
22.01.2019, 00:44 [ТС] | 48 | |||||
Ну на int быстрее чем на byte, но на long что-то как-то медленно. Win 64. Хотя может это из-за того что из под виртуалки сижу...
0
|
Модератор
|
|
22.01.2019, 01:15 | 49 |
Это не от системы зависит, а от процессора.
Основной тип данных для АЛУ процессора - 32 разряда. Может только у новых перешли на 64 (как основной тип) - точно не знаю. Все операции с байтами делаются через приведение к int. Поэтому потеря тактов на этом вполне возможна. Может быть можно как-то указать в настройках оптимизации или небезопасный код, чтобы этого избежать. Но не возился с этим, не было такой потребности.
0
|
7 / 4 / 3
Регистрация: 07.08.2016
Сообщений: 65
|
||||||
22.01.2019, 03:24 [ТС] | 50 | |||||
Протестировал еще один способ, попробовав BitArray из System.Collections;
0
|
22.01.2019, 03:24 | |
22.01.2019, 03:24 | |
Помогаю со студенческими работами здесь
50
отслеживание изменений Отслеживание изменений отслеживание изменений Отслеживание изменений Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |