|
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
|
|||||||||||
Как правильно залочить структуру в массиве?27.08.2019, 17:59. Показов 2833. Ответов 34
Метки нет (Все метки)
Подскажите, как правильно залочить структуру в массиве?
1) Есть структура. Примерно такая,
(Потому и структуру создавал MyEntity , а не класс , чтобы меньше оперативной памяти использовалось. На каждый объект класса идёт больше памяти ). Примерно так, (T в данном случае - может быть структура выше, MyEntity)
Я пытаюсь залочить два значения - Count - потому что именно Count и перезаписывается, а также значение InternalArray[workingVal] -- что есть структура из 5-ти полей. И это логично, ведь если только эти значения будут перезаписываться, то могут быть перезатёрты потоками, если их не залочить. Т.е. может быть такая ситуация 1-й поток получит InternalArray[workingVal] , запишет туда 2 значения, а потом планировщик переключит на другой поток, и он затрёт данные первого потока. Но в результате получаю ошибку - is not a reference type as required by the lock statement Получается, что компилятор не даёт залочить именно эти два значения, потому что это не ссылочные типы. И что тогда оптимальнее всего в плане производительности - лочить весь DynamicArrayIncreasing -- т.е. на время запрещать другим потокам обращаться ко всему массиву? Это неоптимально, если потоку нужно только один элемент массива перезаписать, который - есть структура из 5-ти целочисленных значений. Спасибо.
0
|
|||||||||||
| 27.08.2019, 17:59 | |
|
Ответы с готовыми решениями:
34
Как правильно написать функцию, которая редактирует структуру по полю Name и возвращает новую, исправленную структуру?.. Как правильно передать указатель на структуру, и правильно ее использовать Как залочить MX25L8005 |
|
95 / 74 / 27
Регистрация: 13.08.2018
Сообщений: 203
|
||||||
| 27.08.2019, 19:10 | ||||||
|
Если не хотите использовать классы, то для перезаписи структур можно использовать именованную блокировку по индексу.
1
|
||||||
|
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
|
|||||||
| 27.08.2019, 19:19 [ТС] | |||||||
Т.е. код выше переписывается так и компилируется , если lock заменить на Monitor.Enter + Monitor.Exit ,
1) по сравнению с обычными lock- когда блокируется весь массив, 2) по сравнению с вашим примером, с Mutex . С Mutex я раньше не работал, вы думаете, что пример с Mutex - наиболее быстрый ? (а скорость важна).
0
|
|||||||
|
95 / 74 / 27
Регистрация: 13.08.2018
Сообщений: 203
|
|||||||
| 27.08.2019, 22:28 | |||||||
Вы передаете в метод копию структуры, которая будет упакована в ссылочный тип. Смысла от такой блокировки нет вообще.
1
|
|||||||
|
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
|
||||||
| 28.08.2019, 11:50 [ТС] | ||||||
|
Сначала, хочу разобраться с этими lock- разных типов.
Правильно ли я понимаю? Захватывается object monitor указанного объекта (это может быть и this). Теперь потоки, пытающиеся тоже получить object monitor того же объекта, не получат его, пока исполняется наша критическая секция. То есть, никакой "блокировки объектов" не существует — будет запрещен доступ только в те места, где пытаются получить монитор уже "захваченного" объекта. 1) есть возможность залочить весь объект ( lock {} или что эквивалентно, lock(this) {}), где выполняется данный код, т.е. на время выполнения этого кода в lock - это нехорошо тем, что все другие участки кода, с таким же, lock(this) {} -- выполняться в это время не будут. 2) есть возможность просто объявить критическую секцию, а для этого - создать сцециальный объект для неё и залочить его (в C++ была такая возможность записать некий код в CRITICAL_SECTION, возможно даже ОС, сама создавала некий объект для этого). Опять же, это нехорошо тем, что в данном случае, потоки не смогут писать любые данные , т.е. в этот блок кода не зайдут, а другим потокам, возможно, в этот момент требуются записи совсем в другой элемент массива. 1-й и 2-й случаи показаны в коде ниже --
3) делать упаковку структуры (элемента массива) в некий объект класса и в lock(ob) - указывать этот объект - смысл получается тот же, как во 2- примере выше, т.к. этот объект будет общий для всех потоков, и никак не будет связан со структурой которую хотим залочить. 4) делать упаковку структуры (элемента массива) в некий локальный объект метода, и в lock(ob) - указывать этот объект - смысла вообще никакого нет, т.к. у всех потоков будут разные залоченные объекты, и по сути, никак потоки не будут влиять друг на друга. Т.е. это эквивалентно тому, как если бы вообще ничего не лочили. Таким образом получается, что массив создавал со структурами, а не объектами классов, чтобы памяти меньше использовалось. Но зато нельзя при таком подходе залочить именно элемент массива для критической секции. Можно создать параллельно в том же классе, массив объектов, которые будут - упакованные int, и лочить их - но тогда пропадёт наш выигрыш по используемой памяти - ведь в таком случае, всё равно будут присутствовать N объектов ссылочного типа. (массив из N структур нессылочного типа + массив N объектов ссылочного типа - с таким результатом можно было и сразу N объектов вместо N структур использовать ). C Mutex пока ещё не разобрался. Неужели, позволяет использовать аналоги критических секций как в примере выше, и при этом не надо создавать никаких объектов..
0
|
||||||
|
95 / 74 / 27
Регистрация: 13.08.2018
Сообщений: 203
|
|
| 28.08.2019, 12:37 | |
|
Не видя весь код, трудно что то подсказать. Можно например хранить индексы с которыми ведется работа в массиве, а потоки в залоченом методе будут их проверять, и действовать по ситуации. Думаю это будет лучшим вариантом.
1
|
|
|
|
||||||
| 28.08.2019, 12:50 | ||||||
|
Да при любом подходе нельзя. Вы синхронизируете доступ к элементу массива а не сам элемент массива. Вам явно нужен другой подход. Добавлено через 8 минут UPD: Всё, окей, дошло. Используйте объекты ссылочного типа и будет вам счастье. Что вы там по памяти сэкономить хотите? И для инкремента Count есть уже готовая штука в виде Interlocked.Increment();
1
|
||||||
|
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
|
||||||||||
| 28.08.2019, 13:55 [ТС] | ||||||||||
|
Перед тем как разбираться с Mutex, ещё посмотрел, можно ли здесь использовать синхронизацию,
вообще без блокировок. Если операция атомарная, например чтение-запись типа int - это можно сделать, правда надо использовать Ключевое слово volatile к этому int. VOLATILE м INTERLOCKED . VOLATILE . Ключевое слово volatile означает, что поле может изменить несколько потоков, выполняемых одновременно. Компилятор, среда выполнения или даже аппаратное обеспечение могут изменять порядок операций чтения и записи в расположения в памяти для повышения производительности. К полям, которые объявлены как volatile, такие оптимизации не применяются. Т.е. в случае записи процессор не запишет в кэш ЦП, а запишет сразу в ОП (изменение переменной станет видно всем другим потокам), и т.д. Ключевое слово volatile может применяться к полям следующих типов: Ссылочные типы. (насколько я понял, потому что сам компилятор применит некую блокировку чтобы потоки выполнили как АТОМАРНУЮ операцию --> read-write ссылок на объекты, которые могут быть 8-байтовыми). также, Простые типы, исключая double и long - тогда ключевое слово volatile по сути, позволяет сделать неблокирующую синхронизацию между потоками, потому что операции могут быть выполнены, как атомарные. Структуры, и типы double и long, нельзя снабдить модификатором volatile, потому что для них не гарантируется атомарность операций чтения и записи. Чтобы защитить многопотоковый доступ к полям таких типов, нужно использовать члены класса Interlocked или защиту доступа с помощью инструкции lock. lock - выше рассмотрел, не вариант в плане производительности. INTERLOCKED -- Надо рассмотреть как использовать . C double и long можно использовать, а можно ли применить к струтктуре, создержащей просто 5 простых полей типа long , и баз блокировок добиться аналога атомарности чтения-записи ? С этим пока не разобрался.
т.е. другие структуры. Но именно структуру, которую переписывает какой то поток в этот момент - другие потоки не могли переписать.
5) вариант. Хранить индекс переписываемого элемента массива. Но всё равно не идеальный. Допустим, есть 20 потоков. Иногда они переписывают какой то элемент в массиве. Перед тем как переписать - поток просто записывает int индекс массива, элемент которого (структуру ) он собрался переписать. Операция атомарная. Всё вроде, ок. Поток переписал структуру в массиве, после чего установил индекс в -1 - т.е. ничего не переписывает . Но, если мы будем хранить только 1 индекс, в момент перезаписи элемента массива, тогда пока поток переписывает свой элемент в массиве, другие потоки не смогут переписать другие элементы (хотя 1-й поток в данном случае не мешает) . Хранить же 20 индексов смысла нет, т.к. появляется проверка по 20-ти int, что уже само по себе не атомарная операция. Идеальный же вариант был бы - добиться атомарности перезаписи структуры (так 5 длинных интов всего!) и ничего не лочить..
для переборной алгоритмической задачи (на самом деле их позже, может быть больше 5-ти, но не суть). Это - 5 умножить на 8 == равно 40 байт на элемент в массиве. Длина массива может доходить на миллиарда элементов, и память закончится. Используйте вместо структуры - объекты class (т.е. ссылочные) - и вы получите не 40 байт на элемент в массиве, а где то (уже не помню, равньше когда то тестил) - а чуть ли не в 2 раза больше. И в переборной задаче, мы сможем хранить в 2 раза меньше элементов. Добавлено через 20 минут
Добавлено через 16 минут Ещё заметил, что
Нужно лочить ещё и чтение. Если 1-й поток пытается что то записать по этому элементу, с индексом workingVal, то 2-й поток, пытаясь записать - сюда не зайдёт. Но 3-й поток, который где то в другом месте, читает этот элемент, с индексом workingVal , (а там структура с 5-ю длинными интами). может прочитать 2 инта старые, и 3 перезаписанные например. Поэтому, лочить нужно, и запись и чтение, именно поэлементно, т.е. для одного элемента массива. Т.е. , лочить нужно и чтение. Либо делать операции чтения-записи, для этой структуры как атомарные, (как если бы там один int всего был. Вот для одного такого int определенного со словом volatile - задача была бы решена быстро и без всяких блокировок).
0
|
||||||||||
|
95 / 74 / 27
Регистрация: 13.08.2018
Сообщений: 203
|
|
| 28.08.2019, 14:11 | |
|
SergeyYN, а если работать с массивом указателей на структуры , не устроит ? Указатели можно атомарно переписывать.
0
|
|
|
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
|
||
| 28.08.2019, 14:24 [ТС] | ||
В памяти массив записан как бы, в линейном блоке , так сказать. Т.е. каждая следующая структура находится после предыдущей. (и массив выделялся единым блоком, т.е. одним new). Если каждую структуру выделять в новом месте памяти с помощью new - это ухудшение производительности. У меня что? В методе, прямо в стеке - определена структура, я только вычисляю записываю её данные (в данном случае 5 длинных int). А потом нахожу нужный элемент в массиве структур, и эти 5 длинных int - перезаписываю в структуру-элемент в массиве. Если же каждую структуру хранить в heap разных местах, то придётся выделять для каждой новой структуры память - с помощью new - это очевидно, доп. нагрузка, как минимум на подсистему, занимающуюся организацией и распределением heap (кучи). Хотя в таком случае да, у меня был бы массив указателей в этом DynamicArray классе, и любой указатель можно было бы залочить, тем самым добившись атомарности перезаписи данных в структуре.
0
|
||
|
1123 / 794 / 219
Регистрация: 15.08.2010
Сообщений: 2,185
|
||||
| 28.08.2019, 14:31 | ||||
|
почему не учитываете выигрыш в скорости обращения от использования класса вместо структуры? про производительность опять же сначала нужен аргумент в пользу структуры вместо класса
0
|
||||
|
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
|
||
| 28.08.2019, 14:35 [ТС] | ||
|
Хотя в таком случае да, у меня был бы массив указателей в этом DynamicArray классе, и любой указатель можно было
бы залочить, тем самым добившись атомарности перезаписи данных в структуре. (либо создавать каждый раз новую структуру в другом месте памяти, переписывать указатель, а старую удалять по указателю). Добавлено через 3 минуты КОП
В примере - в массиве используются структуры, длиной в 5 ulong для переборной алгоритмической задачи (на самом деле их позже, может быть больше 5-ти, но не суть). Это - 5 умножить на 8 == равно 40 байт на элемент в массиве. Длина массива может доходить на миллиарда элементов, и память закончится. Используйте вместо структуры - объекты class (т.е. ссылочные) - и вы получите не 40 байт на элемент в массиве, а где то (уже не помню, равньше когда то тестил) - а чуть ли не в 2 раза больше. И в переборной задаче, мы сможем хранить в 2 раза меньше элементов. Именно экономия памяти на больших массивах - и есть аргумент в пользу структуры вместо класса.
0
|
||
|
95 / 74 / 27
Регистрация: 13.08.2018
Сообщений: 203
|
||
| 28.08.2019, 14:36 | ||
|
0
|
||
| 28.08.2019, 14:41 | |
|
0
|
|
|
|
||
| 28.08.2019, 14:45 | ||
|
У вас в любом случае память закончится, на миллиардном массиве или на миллиард сто.
0
|
||
|
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
|
|||||||||||||
| 28.08.2019, 14:58 [ТС] | |||||||||||||
|
maximka777
i-й элемент во внутреннем "линейном массиве структур", т.е. не InternalArray[i] , а некий InternalArray[workingVal] , где workingVal -- переопределяемый номер в зависимости от массива указателей. Тогда, дополнительно 1) Массив указателей, на структуры дополнительно добавит в память, только на +8 байт, на одну доп. сущность в DynamicArrayIncreasing . (что не так существенно, по сравнению со случаем хранения объектов класса вместо структур), 2) структуры , перезаписываются в InternalArray[index] , только для тех index, которых временно нет массиве указателей, pointer[] InternalPointers ? Я правильно понял? И тогда будет достагнута цель - атомарность перезаписи структур, без всяких lock, и без использования ссылочных типов. Если это прокатит, то вариант просто гениальный по своей задумке. Но я ещё не всё продумал по этому поводу, т.е. голова уже кругом идёт.. Могу ошибаться. Cupko , Добавлено через 2 минуты
Тогда и будет видно, что совсем не +8 байт добавляется на ссылочный тип по сравнению со структурой. А намного больше.
0
|
|||||||||||||
|
1123 / 794 / 219
Регистрация: 15.08.2010
Сообщений: 2,185
|
||||
| 28.08.2019, 15:39 | ||||
|
2
|
||||
|
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
|
|||||||||
| 28.08.2019, 15:53 [ТС] | |||||||||
|
Ладно, я вот сейчас сам перепроверил. Это для x64 платформы (в студии указал).
Но это в идеальном случае, только массив создали и объекты. При всякой работе же, с этими объектами, если MyEntity - не структура, а класс, то доп. расходы в системе могут доходить до +30 байт на каждый элемент в массиве! Это значит что? Всего элементов в массиве я смогу хранить почти в 2 раза меньше. КОП Добавлено через 2 минуты
А C++ я уже работал раньше, и знаю, какие там трудности. Добавлено через 4 минуты КОП
Вот же, maximka777 , вкратце написал,
0
|
|||||||||
|
95 / 74 / 27
Регистрация: 13.08.2018
Сообщений: 203
|
||
| 28.08.2019, 16:04 | ||
|
1
|
||
|
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
|
|||||||
| 28.08.2019, 16:05 | |||||||
|
Ну и миллиард элементов на 40 байт каждый — это минимум 40 миллиардов байт или 40 ГБ памяти. Вне зависимости от того, где они хранятся, вам придется пересмотреть подход к работе с такими объемами. Что касается синхронизации, то поскольку вы синхронизируетесь на Count, постольку внутренняя синхронизация на элементе массива смысла не имеет, т.к. нет ситуации, при которой эту проверку выполняло бы больше одного потока. Так что сделайте один закрытый объект для синхронизации и используйте только его:
0
|
|||||||
| 28.08.2019, 16:05 | |
|
Помогаю со студенческими работами здесь
20
Как правильно определить структуру? Как правильно описать структуру БД? Как правильно объявить структуру
Как правильно определить структуру Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
||||
|
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Налог на собак: https:/ / **********/ gallery/ V06K53e
Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf
Пост отсюда. . .
|
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop?
Ниже её машинный перевод.
После долгих разбирательств я наконец-то вернула себе. . .
|
Thinkpad X220 Tablet — это лучший бюджетный ноутбук для учёбы, точка.
Programma_Boinc 23.12.2025
Рецензия / Мнение/ Перевод
Нашел на реддите интересную статью под названием The Thinkpad X220 Tablet is the best budget school laptop period . Ниже её машинный перевод.
Thinkpad X220 Tablet —. . .
|
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта
Симптом:
После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
|
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
|
|
Новый ноутбук
volvo 07.12.2025
Всем привет.
По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне:
Ryzen 5 7533HS
64 Gb DDR5
1Tb NVMe
16" Full HD Display
Win11 Pro
|
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
|
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
|
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов
На странице:
https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/
нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
|
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов.
. . .
|