Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.77/13: Рейтинг темы: голосов - 13, средняя оценка - 4.77
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146

Как правильно залочить структуру в массиве?

27.08.2019, 17:59. Показов 2994. Ответов 34
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Подскажите, как правильно залочить структуру в массиве?

1) Есть структура. Примерно такая,

C#
1
2
3
4
5
6
7
8
public struct MyEntity 
{
        public ulong data0;
        public ulong data1;
        public ulong data2;
        public ulong data3;
        public ulong data4;
}
2) Есть самописный класс, для создания динамических массивов этих структур.
(Потому и структуру создавал MyEntity , а не класс , чтобы меньше оперативной памяти использовалось.
На каждый объект класса идёт больше памяти ).

Примерно так, (T в данном случае - может быть структура выше, MyEntity)

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
public class DynamicArrayIncreasing<T> where T : struct 
{
     // ... 
 
     public ulong Count { get; protected set; }
     public T[] InternalArray { get; set; }
 
     public void AddOrReplace(ref T item , int index)
     {
          ulong workingVal = 0;
          // ... define workingVal
 
          if (!IsMultiThreading)
          {
                 // ...
          }
          else
          {
                lock(Count)
                {
                    lock (InternalArray[workingVal])
                    {
                         InternalArray[workingVal] = item;
                    }
                    Count++;
                }
          }
     }
 
}

Я пытаюсь залочить два значения - Count - потому что именно Count и перезаписывается,
а также значение InternalArray[workingVal] -- что есть структура из 5-ти полей.

И это логично, ведь если только эти значения будут перезаписываться, то могут быть перезатёрты
потоками, если их не залочить. Т.е. может быть такая ситуация 1-й поток получит InternalArray[workingVal] ,
запишет туда 2 значения, а потом планировщик переключит на другой поток, и он затрёт данные первого потока.

Но в результате получаю ошибку -
is not a reference type as required by the lock statement

Получается, что компилятор не даёт залочить именно эти два значения, потому что это не ссылочные типы.
И что тогда оптимальнее всего в плане производительности - лочить весь DynamicArrayIncreasing --
т.е. на время запрещать другим потокам обращаться ко всему массиву?
Это неоптимально, если потоку нужно только один элемент массива перезаписать, который - есть структура из
5-ти целочисленных значений.

Спасибо.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
27.08.2019, 17:59
Ответы с готовыми решениями:

Как правильно написать функцию, которая редактирует структуру по полю Name и возвращает новую, исправленную структуру?..
Нужно отредактировать структуру по выбору пользователя. Проблема заключается в создании функции. Подскажите, а лучше покажите, как...

Как правильно передать указатель на структуру, и правильно ее использовать
Я планирую сделать сортировку, но компилятор начал ругаться &quot;Нет существует подходящей функции преобразования &quot;Student&quot; в...

Как залочить MX25L8005
Всем привет!! Как залочить микруху MX25L8005. Спрашивал на других сайтах. Ответы типа - Микросхемы SPI Flash ROM, поддерживают сигнал...

34
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
28.08.2019, 16:34  [ТС]
Студворк — интернет-сервис помощи студентам
kolorotur
При использовании структур у вас память закончится намного быстрее, чем при использовании классов — банально из-за того, что для массива структур потребуется больше памяти, чем для массива ссылок.
У меня динамический массив, и если уже память выделилась, т.е. +40 байт на структуру ушло в любом случае,
и она может быть использована. В случае class вместо struct, придётся выделить в куче объеект, + 8 байт потеряется
на ссылку в массиве. Т.е. в любом случае тут потери по памяти. (66 байт вместо 40 на один элемент, как я показал выше).

maximka777
Можно запихать в класс по 8 структур и перегрузить индексатор, + 12,5 % большой роли не сыграют, будет золотая середина.
Спасибо, идея тоже хорошая. Обдумываю, плюсы и минусы.

kolorotur
поскольку вы синхронизируетесь на Count, постольку внутренняя синхронизация на элементе массива смысла не имеет, т.к. нет ситуации, при которой эту проверку выполняло бы больше одного потока.
Это только при добавлении нового элемента, я синхронизирую на Count, потому что это значение в любом случае будет увеличено.
Но есть ещё блок - не добавление элемента, а именно замена данных в существующем элементе массива.
Там Count не меняется , и залочить нужно по оптимальному, именно заменяемый элемент (который есть структура),
т.е. сделать по сути, атомарной запись-чтение, именно этой структуры.


C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
     public void AddOrReplace(ref T item , int index)
     {
          ulong workingVal = 0;
          // ... define workingVal
 
          if (!IsMultiThreading)
          {
                 // ...
          }
          else
          {
                //  блок Add.. 
 
                // блок Replace --> 
                lock (InternalArray[workingVal])
                {
                       InternalArray[workingVal] = item;
                }
                
          }
     }
вот примерно аналог такого кода нужен. lock (InternalArray[workingVal]) в данном случае не работает,
потому что этот элемент, с индексом workingVal - является структурой содержащей 5 длинных интов.

Mutex оптимально здесь использовать вместо lock ? Раньше с Mutex не работал..
0
1123 / 794 / 219
Регистрация: 15.08.2010
Сообщений: 2,185
28.08.2019, 16:44
Цитата Сообщение от SergeyYN Посмотреть сообщение
Mutex оптимально здесь использовать вместо lock ? Раньше с Mutex не работал..
над капотом это одно и то же (лок быстрее)

разница лишь в том что мьютекс можно будет чекнуть из дугого приложения/апп домена
1
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
28.08.2019, 17:00  [ТС]
Mutex оптимально здесь использовать вместо lock ? Раньше с Mutex не работал..
КОП
над капотом это одно и то же (лок быстрее)
разница лишь в том что мьютекс можно будет чекнуть из дугого приложения/апп домена
Спасибо. Ну тогда остаются видимо, два подхода,

1) подумать в сторону INTERLOCKED - можно ли с помощью этих возможностей, сделать запись структуры
с 5-тью длинными int - атомарной.

2) делать разбиения на объекты, содержащие несколько структур, примерно так -

maximka777
Можно запихать в класс по 8 структур и перегрузить индексатор, + 12,5 % большой роли не сыграют, будет золотая середина.

Лок всего 8-ми структур (в одном объекте) в таком случае, не приведёт к особому падению производительности, т.к. редко такое
будет, чтобы два потока одновременно пытались что то писать в рядом лежащие структуры.
В любом случае это лучше чем лок, всего массива.
Можно даже не по 8, а по 1000 создавать подмассивы в общем DynamicArray, т.к. если всего элементов -
миллионы, десятки миллионов, то и коллизии на тысячах будут редко происходить.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
28.08.2019, 17:24
Цитата Сообщение от SergeyYN Посмотреть сообщение
У меня динамический массив, и если уже память выделилась, т.е. +40 байт на структуру ушло в любом случае,
и она может быть использована. В случае class вместо struct, придётся выделить в куче объеект, + 8 байт потеряется
на ссылку в массиве. Т.е. в любом случае тут потери по памяти. (66 байт вместо 40 на один элемент, как я показал выше).
Проблема не в общем количестве выделяемой памяти, а в количестве последовательно выделяемой памяти.
Для массива структур ее требуется больше, значит намного выше шанс, что такого объема последовательной памяти не будет в наличии, что приведет к OutOfMemoryException.
Вот такой вот получается парадокс: в целом памяти при использовании структур потребуется меньше, но при этом существенно возрастает вероятность падения приложения из-за нехватки памяти.

Массивы ссылочных типов этому меньше подвержены, т.к. занимают меньше места.

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

Цитата Сообщение от SergeyYN Посмотреть сообщение
Но есть ещё блок - не добавление элемента, а именно замена данных в существующем элементе массива.
Можно завести для этих целей отдельны объект синхронизации, но если вам нужна именно атомарность, то вариантов не много:
1. Использовать ссылочные типы
2. Держать отдельный массив объектов синхронизации — по одному для каждого элемента массива (фу).
3. Переписать алгоритм таким образом, чтобы он не требовал синхрониации.
3
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
28.08.2019, 17:44  [ТС]
Проблема не в общем количестве выделяемой памяти, а в количестве последовательно выделяемой памяти.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
28.08.2019, 17:50
Цитата Сообщение от SergeyYN Посмотреть сообщение
Проблема не в общем количестве выделяемой памяти, а в количестве последовательно выделяемой памяти.
Во-во, я о том же!
0
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
28.08.2019, 17:52  [ТС]
kolorotur
Во-во, я о том же!
Моё сообщение выше - можно удалить, оно неполное, случайно не та кнопка нажалась кажется.

Проблема не в общем количестве выделяемой памяти, а в количестве последовательно выделяемой памяти.
Для массива структур ее требуется больше
Я выделяю память для массива структур, именно тогда когда они мне действительно нужны.
Если вы имеете в виду, что в случае массива ссылок на объекты может быть некий выигрыш, то он может
быть оттого, что по некоторым ссылкам реально объекты не выделяются. У меня такого случая быть не может.
Впрочем, позже, как создам, приведу полный код своего класса, отвечающего за динамический массив,
тогда будет всё понятнее.

1) подумать в сторону INTERLOCKED - можно ли с помощью этих возможностей, сделать запись структуры
с 5-тью длинными int - атомарной.
Похоже на то, что это не вариант.
Во-первых,
https://docs.microsoft.com/ru-... ___0____0_


T - Тип, используемый для location1 и value. Этот тип должен быть ссылочным типом.
для метода Exchange<T>(T, T) класса Interlocked .

А во-вторых, обдумывая алгоритмы, прихожу к выводу, что иногда придётся и вовсе сразу 2 разных элемента
(и не рядом лежащих) в массиве структур перезаписывать, так сказать "одной транзакцией", т.е. лдя посторонних потоков,
должны быть переписаны сразу оба элемента, либо не переписан ни один из них..

Придётся создавать подмассивы в классе глобального динамического массива, и лочить именно их.
Позже, покажу окончательный код своего многопоточно-безопасного класса, DynamicArrayIncreasing.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
28.08.2019, 18:06
Цитата Сообщение от SergeyYN Посмотреть сообщение
Я выделяю память для массива структур, именно тогда когда они мне действительно нужны.
По большому счету не имеет значения когда именно память под массив выделяется: массивы струтур более склонны обрушить приложение из-за нехватки памяти, чем массивы ссылочных типов. Разумеется, если размер структуры у вас больше, чем размер ссылки. А он больше.

Цитата Сообщение от SergeyYN Посмотреть сообщение
Если вы имеете в виду, что в случае массива ссылок на объекты может быть некий выигрыш, то он может
быть оттого, что по некоторым ссылкам реально объекты не выделяются.
Нет, дело не в ссылках, а в количестве памяти, необходимой для массива структур и для массива ссылок.
Для массива ссылок это всегда n*[размер ссылки], где размер ссылки — 4 или 8 байт, в зависимости от целевой платформы.
Для массива структур это n*[размер структуры], что в вашем случае 40 байт.
n в обоих случаях — количество элементов.

Как видите, при одном и том же количестве элементов массив ваших структур будет занимать в 10 раз больше памяти на 32-битной системе и в 5 раз больше памяти на 64-битной системе, чем массив ссылок, что существенно повышает риск словить OutOfMemoryException при попытке такой массив создать, хоть и общее количество памяти для массива+экземпляров при использовании структур действительно будет меньше.

Другими словами, если главной причиной использовать структуры вместо массивов озвучивается экономия памяти, то при большом количестве элементов она теряет смысл, т.к. воспользоваться этой экономией вам все равно не получится.
Ну а при малых количествах элементов экономия и подавно бессмысленна.
1
28.08.2019, 18:19

Не по теме:

Цитата Сообщение от SergeyYN Посмотреть сообщение
Моё сообщение выше - можно удалить, оно неполное, случайно не та кнопка нажалась кажется.
используйте правку и пишите del чтобы удалили

чтобы цитировать - выделите тест сообщения и появится прямоугольная кнопочка для вставки цитаты, тогда все будет с именами как у людей

0
 Аватар для m0nax
1274 / 975 / 113
Регистрация: 12.01.2010
Сообщений: 1,971
28.08.2019, 19:40
для случаев когда надо в основном читать, но иногда и менять значение есть хорошая штука - ReaderWriterLockSlim
1
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
28.08.2019, 22:17  [ТС]
Цитата Сообщение от КОП Посмотреть сообщение
используйте правку и пишите del чтобы удалили
"правку" я уже не вижу.

Цитата Сообщение от m0nax Посмотреть сообщение
для случаев когда надо в основном читать, но иногда и менять значение есть хорошая штука - ReaderWriterLockSlim
Спасибо, почитаю, что это такое. Впервые вижу.

Добавлено через 23 минуты
Цитата Сообщение от kolorotur Посмотреть сообщение
Как видите, при одном и том же количестве элементов массив ваших структур будет занимать в 10 раз больше памяти на 32-битной системе и в 5 раз больше памяти на 64-битной системе, чем массив ссылок, что существенно повышает риск словить OutOfMemoryException при попытке такой массив создать, хоть и общее количество памяти для массива+экземпляров при использовании структур действительно будет меньше.
Я понимаю, что риск словить OutOfMemoryException выше. Но в моём случае - мой объект класса
class DynamicArrayIncreasing<T> where T : struct
(точне, позже наследуемый от него объект, который и будет использоваться), будет знать параметры конфигурации системы
Т.е. перед полным перебором, пользователь введёт число N, которое означает - N гигабайт которые он готов пожертвовать
для перебора, ну а если уж будет ошибка в этой конфигурации, и , DynamicArrayIncreasing словит OutOfMemoryException -

то проблема будет не в моём классе DynamicArrayIncreasing, а в данных, которые ввёл пользователь,
как параметры алгоритмической переборной задачи.

Добавлено через 30 минут
Используется ReaderWriterLockSlim для защиты ресурса, который считывается несколькими потоками и записывается в один поток за раз.

(цитата с docs.microsoft.com)
Это похоже, камень преткновения. У меня, нужно обеспечить доступ многим потокам, не только читать,
а также, обеспечить многим потокам и писать (т.е.е изменять данные).
Могу ошибаться (в плане того что ReaderWriterLockSlim может помочь, даже в случае если много потоков могут и
читать и писать.. ).
0
 Аватар для m0nax
1274 / 975 / 113
Регистрация: 12.01.2010
Сообщений: 1,971
29.08.2019, 11:57
Цитата Сообщение от SergeyYN Посмотреть сообщение
(цитата с docs.microsoft.com)
Это похоже, камень преткновения. У меня, нужно обеспечить доступ многим потокам, не только читать,
а также, обеспечить многим потокам и писать (т.е.е изменять данные).
Могу ошибаться (в плане того что ReaderWriterLockSlim может помочь, даже в случае если много потоков могут и
читать и писать.. ).
изменять один и тот же элемент несколько потоков никак не могут, так не бывает
массив может быть один, но в любую из ячеек в каждый момент времени писать может только 1 поток. а читать сколько угодно, вот как раз ReaderWriterLockSlim помогает аккуратно это делать
1
Эксперт .NETАвтор FAQ
 Аватар для Storm23
10428 / 5158 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
30.08.2019, 10:41
SergeyYN,
Как вариант:

C#
1
2
3
4
5
6
7
8
9
10
        const int factor = 101;
        var syncObjects = Enumerable.Range(0, factor).Select(i => new object()).ToArray();
        
        ....
 
        // блок Replace --> 
        lock (syncObjects[workingVal % factor])
        {
            InternalArray[workingVal] = item;
        }
1
83 / 1 / 0
Регистрация: 08.11.2017
Сообщений: 146
30.08.2019, 14:52  [ТС]
Цитата Сообщение от m0nax Посмотреть сообщение
но в любую из ячеек в каждый момент времени писать может только 1 поток. а читать сколько угодно, вот как раз ReaderWriterLockSlim помогает аккуратно это делать
Не может читать сколько угодно потоков. У меня в массиве хранятся структуры, которые не прочитаешь и не запишешь одной атомарной операцией. Там в структуре допустим, 5 интов. Первый поток начал записывать, и заблокировал доступ другим потокам , пытающимся тоже записать. Записал 2 инта , а 3 инта в структуре ещё на записал. И планировщик приостановил этот поток. Тут другой поток читает без всяких блокировок, и получае "грязные данные" - 2 инта от одной сущности, и 3 инта - от новой, ещё не до конца записанной сущности.


Цитата Сообщение от m0nax Посмотреть сообщение
изменять один и тот же элемент несколько потоков никак не могут, так не бывает
массив может быть один, но в любую из ячеек в каждый момент времени писать может только 1 поток. а читать сколько угодно,
Именно потому "читать сколько угодно" - могут только тогда , когда никакой поток ничего не пишет.
Значит , пишущий поток должен блокировать читающих, а читающие не должны блкировать читающих, и вот как это сделать?
У меня блокируют и читающие и пишущие, т.к. захватывают object monitor указанного объекта, в данном случае -
внутреннего подмассива.

Я обещал привести исходники своего DynamicArrayIncreasing -
класса, позволяющий работать с многопоточно-безопасным, динамическим массивом структур.
(и максимально производительным).
И как здесь конкретно ReaderWriterLockSlim может помочь , что то ещё более оптимально сделать?
Спасибо.


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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 
namespace Algorithmictree._0.Common
{
 
    
    public interface ISizeDefinable
    {
        long SizeOfBytes();
    }
        
    
    public class DynamicNode<T> where T : struct, ISizeDefinable
    {
        public T[] internalArray { get; set; }
 
        public const long Capacity = 10000;
        // 10 000 - выделяем такими блоками. Т.к. тип  используется в основном для 
        // DynamicArrayIncreasing<T> where T : struct, ISizeDefinable  
        // где T - структуры размером от 16 байт (2 ulong) , до структур размером 64 байта (8 ulong), 
        // это СПЕЦИФИКА ЗАДАЧ, решаемых даннми классами, (хотя DynamicArrayIncreasing можно использовать 
        // и для любых структур, любых размеров. ) . Поскольку для основных задач зачем создается класс - 
        // максимумальная структура может именть размером 64 байта (это 8 ulong), то 
        // максимум на создание этого первого массива, будет не более  64 байта умноженное  на 10 тысяч, 
        // равно 640 килобайт, что совсем несущественно для переборной задачи, (т.е. стартовый размер первого блока
        // где гарантированно выделится память будет равен - будет равно 640 КБ ) а  динамический массив может 
        // далее увеличиваться так, что будет занимать многие ГБ оперативной памяти! 
        // В случае если, будут использоваться структуры размером даже в 10 килобайт, всё равно, тогда 
        // стартовый размер в памяти, первого блока, будет порядно 100 МБ, что также не существенно, 
        // если данный код пишется для переборных задач где подразумеваются многие гигабайты используемой памяти. 
 
 
        public DynamicNode()
        {
            internalArray = new T[Capacity];
        }
    }   // class DynamicNode<T>
 
 
 
 
    // 1) МНОГОПОТОЧНО-безопасный DynamicArrayIncreasing. 
    // 2) особенность -  элементы в массив только добавляются не удаляются. 
    // Increasing - означает возрастающий, и убывать не может.  
    // Но  есть возможность и ЗАМЕНИТЬ существующий элемент, этого достаточно лдя алгоритмических задач перебора,
    // т.е. будет известно, какие лишние элементы ("дырки" в массиве), которые где угодно в середине массива 
    // можно перезаписать. 
    public class DynamicArrayIncreasing<T> where T : struct, ISizeDefinable
    {
 
        public bool IsMultiThreading { get; protected set; }
 
        public const long MaxCapacity = 100000000000L;
        // 100 миллиардов максимум элементов, которые может содержать класс DynamicArrayIncreasing
        // а  так как внутренний блок занимает 10 000 элементов , то всего необходимых блоков равно 100 млрд / 10 тысяч ==  10000000 (10 млн)
        // каждый блок - это просто ссылка (8 байт) на объект (ссылочный тип, а объект - массив) - доп. расходы памяти на старте программы, 
        // составят эти 80 МБ . 
 
        protected DynamicNode<T>[] externalArray { get; set; }
        protected T defaultExemplar;
 
        
        private long count;  
        //     значение  текущего  количества элементов в массиве. 
        // 1. Если читается-пишется _Count совместно с перезаписью некоего элемента во внутренних массивах, (метод Add например), 
        //    то блокировать нужно весь объект  DynamicArrayIncreasing , т.е. lock(this) , потому что два объекта должны быть 
        //    обработаны как атомарная операция, нельзя чтобы например, элемент массива перезаписался, потом поток остановился, 
        //    а затем другой поток читает устаревшее и некорректное значение _Count 
        // 2. Если же для каких то целей, нужно только прочитать или изменить значение _Count , не меняя  при этом больше ничего, 
        //    для этого ниже есть Property, в котором чтение и запись происходит как атомарная операция с Interlocked, 
        //    потому что иначе, операции с long - вообще говоря, не являются атомарными.         
 
            
        public long Count
        {
            get
            {                
                long location = 0;
 
                // location = count;
                Interlocked.Exchange(ref location, count);
 
                //return count;
                return location;
            }
            protected set
            {
                //count = value;
                Interlocked.Exchange(ref count, value);
            }
        }
 
 
        // constructor 
        public DynamicArrayIncreasing(bool isMultiThreading = true)
        {
            IsMultiThreading = isMultiThreading;  // по умолчанию многопоточно-безопасный. 
 
            count = 0;
            externalArray = new DynamicNode<T>[10000000L];
            // 10.000.000 внешних  elements массивов. (по 10 000 элементов в каждом может быть позже - см выше) 
 
            defaultExemplar = default(T);
        }   // constructor 
 
        
 
        public long SizeOfMegabytes
        {
            get
            {
                long sizeOfExemplar = (defaultExemplar as ISizeDefinable).SizeOfBytes();
                long countElements = Count;
 
                long countFilledBlocks = countElements / 10000L;   //  10 тысяч - наш объект  DynamicNode<T> 
                long sizeInBytes = (countFilledBlocks * 10000L * sizeOfExemplar ) + (8L * 10000000L) + (12L * countFilledBlocks);
 
                // При старте программы, вся занимаемая память будет равна 80 МБ, плюс то что по первому слагаемому - 
                // зависит от размера струткруры, 10 000 умножить на размер структуры. 
                // в формуле все слагаемые и мнодители имеют тип long, потому и числовые - это литералы с буквой L . 
                // при старте программы - выделяется 10000000L (10 млн) ссылок ипа DynamicNode<T> в объекте-массиве  externalArray , 
                // и каждая такая ссылка, имеет размер 8 байт, до того как по ней выделится новый объект - внутренний массив. 
                // Также, в начале countFilledBlocks == 1, а потому, в массиве externalArray один элемент получит
                // дополнительные 12 байт. 
                // После того как массив externalArray полностью заполнится объектами , на каждый countFilledBlocks добавится 12 байт,
                // доп. затраты на объект по сравнению с пустой ссылкой = 12 байт. 
                // (На объект идёт в 64-битной системе, кроме  8 на саму ссылку на объект уже выше определенной, 
                // ещё 4 на синк. блок + 8 на хедер .)  Поэтому если заполнятся все countFilledBlocks реальными объектами,  т.е. 
                // countFilledBlocks == 10000000L , последние два слагаемые будут равны 20 байтам умноженным на 10 млн, т.е. 200 МБ - 
                // это максимум памяти, на доп. расходы. 
                // Но это ничто по сравнению сравнению с гигабайтами-терабайтами реальных данных, которые будут использщоваться при переборе. 
                // Первое же слагаемое понятно - сами струткруры занимают sizeOfExemplar байт, каждый новый блок - в 10 000 раз больше, 
                // и самих блоков countFilledBlocks может быть до 10 млн. 
 
                long sizeOfMegabytes = sizeInBytes / 1048576;
                return sizeOfMegabytes;
            }
        }   // public long SizeOfMegabytes
 
 
        public void Add(ref T item)
        {
            // почему в Add - см. выше. Изменяются два объекта, нужно делать как атомарную операцию.
            // а могут измняться даже три объекта, в случае если ещё и выделяться новый блок-массив. 
 
            if (IsMultiThreading)
                Monitor.Enter(this);  // аналог lock(this)
            {
                long count = Count;  // атомарное стение Property Count 
                long workingBlock = count / 100000L;
                long workingVal = count % 100000L;
 
                // если понадобился новый блок .
                if (workingVal == 0)
                {
                    externalArray[workingBlock] = new DynamicNode<T>();
                }
 
                externalArray[workingBlock].internalArray[workingVal] = item;
                
                Count++;
            }   // lock 
 
            if (IsMultiThreading)
                Monitor.Exit(this);  // аналог lock(this)
 
        }   // public void Add(T item)
 
 
 
        // 1) Решил через индексатор не делать, т.к. в set приходит value, которое является структурой, в значит 
        // скорее всего это value - переписывается (доп расходы на переписывание полей струткрур), а потом 
        // повторно должно переписаться в элемент массива (который тоже является структурой). 
        // Данный же метод Replace - получает ref  - т.е. ссылку на структуру, которая была определена где-то
        // в стеке вызывающего метода, потому лишнего копирования полей структуры не происходит, оно происходит 
        // только один рах - при записи в массив , т.е. в internalArray [...]
        // 2) ОБЯЗАТЕЛЬНОЕ условие - параметр long index - должен быть МЕНЬШЕ чем Count ! Т.е. перезаписываемый 
        // элемент должен уже существовать в массиве. 
        public void Replace(ref T item, long index)
        {
            long workingBlock = index / 10000L;            
 
            // блокировать полностью this не обязательно, производительнее заблокировать только один объект 
            // внутреннего массива, чтобы другие потоки могли работать  с другими блоками при перезаписи. 
 
            if (IsMultiThreading)
                Monitor.Enter(externalArray[workingBlock].internalArray );  // аналог lock(...) 
            
            {
                long workingVal = index % 10000L;
                externalArray[workingBlock].internalArray[workingVal] = item;
            }
 
            if (IsMultiThreading)
                Monitor.Exit(externalArray[workingBlock].internalArray);
 
 
        }   // public void Replace(ref T item, long index)
        
 
 
        // индексатор - только GET - по выше описанной причине. (см Replace метод)
        public T this[long index]
        {
            get
            {
                // чтение элемента массива, который есть струтктура, как и запись - 
                // должно быть атомарной операцией, чтобы не получилось, что один поток 
                // записывает структуру, в то же время как другой поток её читает. 
                // Так можно прочитать "грязные данные", т.е. некоторые устаревшие поля 
                // в структуре. 
 
                T retValue = default(T);
 
                long workingBlock = index / 100000L;
 
                if (IsMultiThreading)
                    Monitor.Enter(externalArray[workingBlock].internalArray);  // аналог lock(...) 
                {
                    long workingVal = index % 100000L;
                    retValue = externalArray[workingBlock].internalArray[workingVal];
                }
                if (IsMultiThreading)
                    Monitor.Exit(externalArray[workingBlock].internalArray);  // аналог lock(...) 
 
 
 
                return retValue;
            }
        }
 
 
    }   //class DynamicArrayIncreasing<T> where T : struct, ISizeDefinable
 
 
    
 
}
0
1123 / 794 / 219
Регистрация: 15.08.2010
Сообщений: 2,185
30.08.2019, 17:25
Цитата Сообщение от SergeyYN Посмотреть сообщение
Тут другой поток читает без всяких блокировок
другой поток не прочитает заблокированные для записи данные, но сможет прочитать, если други потоки тоже только читают

Добавлено через 52 секунды
Цитата Сообщение от SergeyYN Посмотреть сообщение
Значит , пишущий поток должен блокировать читающих, а читающие не должны блкировать читающих, и вот как это сделать?
ReaderWriterLockSlim
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
30.08.2019, 17:25

Как правильно определить структуру?
Доброго всем времени! У меня возник вопрос по структурам: .data WORKER struc ;информация о сотруднике nam db 30 dup (' ') ...

Как правильно описать структуру БД?
Я делаю чат и мне понадобилась БД для списка пользователей. Там будут в частности администраторы и баны. Я использую Entity Framework и...

Как правильно объявить структуру
Есть вот такая вот структурка: typedef struct { // 1st byte (event code) union { struct { ...

Как правильно объявить структуру
Всем доброго времени суток.Есть задача:Составить программу формирования данных об успеваемости студентов по дисциплине: фамилия И.О., 5...

Как правильно определить структуру
код в модуле: typedef struct { BaseType *Buf; // Массив элементов базового типа unsigned Kbuf; /*...


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

Или воспользуйтесь поиском по форуму:
35
Ответ Создать тему
Новые блоги и статьи
Был праздник вчера, а я и не знал.
kumehtar 28.07.2026
27. 07. 2026г. Intel Core 2 Duo исполнилось 20 лет Новости компьютерного мира и их обсуждение (4) Салют, шампанское, овации! :drink:
Нейтральные знания, чистый код - бла-бла-бла-бла, на самом деле кликбейт и самореклама, плагиат, и вот почему
Hrethgir 27.07.2026
То-есть отклонение такой публикации говорит само за себя, и пусть только возьмут на вооружение после отклонения публикации - это будет чистейшим актом плагиата. Отклонял Хабр. Дословно, отклонённая. . .
тв 16 бой ии
anaschu 27.07.2026
Великий Перелом ИИ: Как уравнения ОДУ Radau дожали цензурные фильтры Алисы Фиксируем в мемофонде Теории Всего беспрецедентный факт в истории ИИ-зондирования. В затяжном многораундовом. . .
мв 15. непроверенное, возможно, глюк
anaschu 27.07.2026
НАУЧНО-АНАЛИТИЧЕСКИЙ ОТЧЕТ. РАЗДЕЛ 1. 1: «НАУКА» (РАСШИРЕННАЯ СТЕХИОМЕТРИЧЕСКАЯ И ГЕНЕТИЧЕСКАЯ ВЕРСИЯ)Тема: Теоретическое обоснование инвариантности 19-мерного тензорного ядра непрерывных ОДУ и. . .
Очистка реквизитов и табличных частей документа при копировании (вариант 2)
Maks 26.07.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРаботу", разработанного в КА2. Задача: Заменить алгоритм запрета копирования документов для сотрудников с ролью "Стажер",. . .
Доктрина интенционального знания - Доктрина для портала "Срез".
Hrethgir 25.07.2026
Может найдётся кто захочет оценить доктрину. . . Написания правил участия для меня роскошь, требующая лимита времени, поэтому все сообщения не прошедшие модерацию будут видны только участникам портала,. . .
сукцессия 44. Решил подать на припринт в межународные сервисы препринтов. Но нужно одобрение от ученых
anaschu 25.07.2026
Английский вариант. Пока кто то не одобрит мою личность, мне не получиться это опубликовать на препринте. Но заявку на публикацию статьи я сегодня подам.
сукцессия 43. Вторая научная статья за месяц- прайминг и гатгил
anaschu 25.07.2026
две стороны одной монеты
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru