Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
ConcurrentBag.cs
Go to the documentation of this file.
6
8
10[DebuggerDisplay("Count = {Count}")]
12{
13 private sealed class WorkStealingQueue
14 {
15 private volatile int _headIndex;
16
17 private volatile int _tailIndex;
18
19 private volatile T[] _array = new T[32];
20
21 private volatile int _mask = 31;
22
23 private int _addTakeCount;
24
25 private int _stealCount;
26
27 internal volatile int _currentOp;
28
29 internal bool _frozen;
30
31 internal readonly WorkStealingQueue _nextQueue;
32
33 internal readonly int _ownerThreadId;
34
35 internal bool IsEmpty => _headIndex - _tailIndex >= 0;
36
37 internal int DangerousCount
38 {
39 get
40 {
43 return addTakeCount - stealCount;
44 }
45 }
46
52
54 {
55 bool lockTaken = false;
56 try
57 {
59 int num = _tailIndex;
60 if (num == int.MaxValue)
61 {
62 _currentOp = 0;
63 lock (this)
64 {
66 num = (_tailIndex = num & _mask);
68 }
69 }
71 if (!_frozen && headIndex - (num - 1) < 0 && num - (headIndex + _mask) < 0)
72 {
73 _array[num & _mask] = item;
74 _tailIndex = num + 1;
75 }
76 else
77 {
78 _currentOp = 0;
81 int num2 = num - headIndex;
82 if (num2 >= _mask)
83 {
84 T[] array = new T[_array.Length << 1];
85 int num3 = headIndex & _mask;
86 if (num3 == 0)
87 {
88 Array.Copy(_array, array, _array.Length);
89 }
90 else
91 {
92 Array.Copy(_array, num3, array, 0, _array.Length - num3);
93 Array.Copy(_array, 0, array, _array.Length - num3, num3);
94 }
95 _array = array;
96 _headIndex = 0;
97 num = (_tailIndex = num2);
98 _mask = (_mask << 1) | 1;
99 }
100 _array[num & _mask] = item;
101 _tailIndex = num + 1;
102 if (num2 == 0)
103 {
105 }
107 _stealCount = 0;
108 }
109 checked
110 {
112 }
113 }
114 finally
115 {
116 _currentOp = 0;
117 if (lockTaken)
118 {
119 Monitor.Exit(this);
120 }
121 }
122 }
123
124 internal void LocalClear()
125 {
126 lock (this)
127 {
128 if (_headIndex - _tailIndex < 0)
129 {
130 _headIndex = (_tailIndex = 0);
133 }
134 }
135 }
136
137 internal bool TryLocalPop([MaybeNullWhen(false)] out T result)
138 {
139 int tailIndex = _tailIndex;
140 if (_headIndex - tailIndex >= 0)
141 {
142 result = default(T);
143 return false;
144 }
145 bool lockTaken = false;
146 try
147 {
148 _currentOp = 2;
150 if (!_frozen && _headIndex - tailIndex < 0)
151 {
152 int num = tailIndex & _mask;
153 result = _array[num];
154 if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
155 {
156 _array[num] = default(T);
157 }
159 return true;
160 }
161 _currentOp = 0;
162 Monitor.Enter(this, ref lockTaken);
163 if (_headIndex - tailIndex <= 0)
164 {
165 int num2 = tailIndex & _mask;
166 result = _array[num2];
167 if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
168 {
169 _array[num2] = default(T);
170 }
172 return true;
173 }
174 _tailIndex = tailIndex + 1;
175 result = default(T);
176 return false;
177 }
178 finally
179 {
180 _currentOp = 0;
181 if (lockTaken)
182 {
183 Monitor.Exit(this);
184 }
185 }
186 }
187
188 internal bool TryLocalPeek([MaybeNullWhen(false)] out T result)
189 {
190 int tailIndex = _tailIndex;
191 if (_headIndex - tailIndex < 0)
192 {
193 lock (this)
194 {
195 if (_headIndex - tailIndex < 0)
196 {
197 result = _array[(tailIndex - 1) & _mask];
198 return true;
199 }
200 }
201 }
202 result = default(T);
203 return false;
204 }
205
206 internal bool TrySteal([MaybeNullWhen(false)] out T result, bool take)
207 {
208 lock (this)
209 {
210 int headIndex = _headIndex;
211 if (take)
212 {
213 if (headIndex - (_tailIndex - 2) >= 0 && _currentOp == 1)
214 {
215 SpinWait spinWait = default(SpinWait);
216 do
217 {
218 spinWait.SpinOnce();
219 }
220 while (_currentOp == 1);
221 }
223 if (headIndex < _tailIndex)
224 {
225 int num = headIndex & _mask;
226 result = _array[num];
227 if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
228 {
229 _array[num] = default(T);
230 }
231 _stealCount++;
232 return true;
233 }
235 }
236 else if (headIndex < _tailIndex)
237 {
238 result = _array[headIndex & _mask];
239 return true;
240 }
241 }
242 result = default(T);
243 return false;
244 }
245
246 internal int DangerousCopyTo(T[] array, int arrayIndex)
247 {
248 int headIndex = _headIndex;
250 for (int num = arrayIndex + dangerousCount - 1; num >= arrayIndex; num--)
251 {
252 array[num] = _array[headIndex++ & _mask];
253 }
254 return dangerousCount;
255 }
256 }
257
258 private sealed class Enumerator : IEnumerator<T>, IDisposable, IEnumerator
259 {
260 private readonly T[] _array;
261
262 private T _current;
263
264 private int _index;
265
266 public T Current => _current;
267
268 object IEnumerator.Current
269 {
270 get
271 {
272 if (_index == 0 || _index == _array.Length + 1)
273 {
275 }
276 return Current;
277 }
278 }
279
280 public Enumerator(T[] array)
281 {
282 _array = array;
283 }
284
285 public bool MoveNext()
286 {
287 if (_index < _array.Length)
288 {
290 return true;
291 }
292 _index = _array.Length + 1;
293 return false;
294 }
295
296 public void Reset()
297 {
298 _index = 0;
299 _current = default(T);
300 }
301
302 public void Dispose()
303 {
304 }
305 }
306
308
310
312
313 public int Count
314 {
315 get
316 {
317 if (_workStealingQueues == null)
318 {
319 return 0;
320 }
321 bool lockTaken = false;
322 try
323 {
325 return DangerousCount;
326 }
327 finally
328 {
330 }
331 }
332 }
333
334 private int DangerousCount
335 {
336 get
337 {
338 int num = 0;
339 for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue)
340 {
341 num = checked(num + workStealingQueue.DangerousCount);
342 }
343 return num;
344 }
345 }
346
347 public bool IsEmpty
348 {
349 get
350 {
353 {
355 {
356 return false;
357 }
359 {
360 return true;
361 }
362 }
363 bool lockTaken = false;
364 try
365 {
367 for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue)
368 {
369 if (!workStealingQueue.IsEmpty)
370 {
371 return false;
372 }
373 }
374 }
375 finally
376 {
378 }
379 return true;
380 }
381 }
382
383 bool ICollection.IsSynchronized => false;
384
385 object ICollection.SyncRoot
386 {
387 get
388 {
390 }
391 }
392
393 private object GlobalQueuesLock => _locals;
394
396 {
398 }
399
413
418
420 {
421 Add(item);
422 return true;
423 }
424
425 public bool TryTake([MaybeNullWhen(false)] out T result)
426 {
428 if (currentThreadWorkStealingQueue == null || !currentThreadWorkStealingQueue.TryLocalPop(out result))
429 {
430 return TrySteal(out result, take: true);
431 }
432 return true;
433 }
434
435 public bool TryPeek([MaybeNullWhen(false)] out T result)
436 {
438 if (currentThreadWorkStealingQueue == null || !currentThreadWorkStealingQueue.TryLocalPeek(out result))
439 {
440 return TrySteal(out result, take: false);
441 }
442 return true;
443 }
444
446 {
447 WorkStealingQueue workStealingQueue = _locals.Value;
448 if (workStealingQueue == null)
449 {
450 if (!forceCreate)
451 {
452 return null;
453 }
454 workStealingQueue = CreateWorkStealingQueueForCurrentThread();
455 }
456 return workStealingQueue;
457 }
458
460 {
462 {
464 WorkStealingQueue workStealingQueue = ((workStealingQueues != null) ? GetUnownedWorkStealingQueue() : null);
465 if (workStealingQueue == null)
466 {
467 workStealingQueue = (_workStealingQueues = new WorkStealingQueue(workStealingQueues));
468 }
469 _locals.Value = workStealingQueue;
470 return workStealingQueue;
471 }
472 }
473
475 {
477 for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue)
478 {
479 if (workStealingQueue._ownerThreadId == currentManagedThreadId)
480 {
481 return workStealingQueue;
482 }
483 }
484 return null;
485 }
486
487 private bool TrySteal([MaybeNullWhen(false)] out T result, bool take)
488 {
489 if (CDSCollectionETWBCLProvider.Log.IsEnabled())
490 {
491 if (take)
492 {
493 CDSCollectionETWBCLProvider.Log.ConcurrentBag_TryTakeSteals();
494 }
495 else
496 {
497 CDSCollectionETWBCLProvider.Log.ConcurrentBag_TryPeekSteals();
498 }
499 }
500 while (true)
501 {
504 bool num2;
506 {
507 if (TryStealFromTo(currentThreadWorkStealingQueue._nextQueue, null, out result, take))
508 {
509 goto IL_0078;
510 }
512 }
513 else
514 {
516 }
517 if (!num2)
518 {
520 {
521 break;
522 }
523 continue;
524 }
525 goto IL_0078;
526 IL_0078:
527 return true;
528 }
529 return false;
530 }
531
533 {
534 for (WorkStealingQueue workStealingQueue = startInclusive; workStealingQueue != endExclusive; workStealingQueue = workStealingQueue._nextQueue)
535 {
536 if (workStealingQueue.TrySteal(out result, take))
537 {
538 return true;
539 }
540 }
541 result = default(T);
542 return false;
543 }
544
545 public void CopyTo(T[] array, int index)
546 {
547 if (array == null)
548 {
550 }
551 if (index < 0)
552 {
554 }
555 if (_workStealingQueues == null)
556 {
557 return;
558 }
559 bool lockTaken = false;
560 try
561 {
564 if (index > array.Length - dangerousCount)
565 {
567 }
568 try
569 {
571 }
573 {
574 throw new InvalidCastException(ex.Message, ex);
575 }
576 }
577 finally
578 {
580 }
581 }
582
584 {
585 int num = index;
586 for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue)
587 {
588 num += workStealingQueue.DangerousCopyTo(array, num);
589 }
590 return num - index;
591 }
592
594 {
595 if (array is T[] array2)
596 {
598 return;
599 }
600 if (array == null)
601 {
603 }
604 ToArray().CopyTo(array, index);
605 }
606
607 public T[] ToArray()
608 {
609 if (_workStealingQueues != null)
610 {
611 bool lockTaken = false;
612 try
613 {
616 if (dangerousCount > 0)
617 {
618 T[] array = new T[dangerousCount];
619 int num = CopyFromEachQueueToArray(array, 0);
620 return array;
621 }
622 }
623 finally
624 {
626 }
627 }
628 return Array.Empty<T>();
629 }
630
631 public void Clear()
632 {
633 if (_workStealingQueues == null)
634 {
635 return;
636 }
639 {
642 {
643 return;
644 }
645 }
646 bool lockTaken = false;
647 try
648 {
650 for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue)
651 {
652 T result;
653 while (workStealingQueue.TrySteal(out result, take: true))
654 {
655 }
656 }
657 }
658 finally
659 {
661 }
662 }
663
665 {
666 return new Enumerator(ToArray());
667 }
668
673
674 private void FreezeBag(ref bool lockTaken)
675 {
678 for (WorkStealingQueue workStealingQueue = workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue)
679 {
680 Monitor.Enter(workStealingQueue, ref workStealingQueue._frozen);
681 }
684 {
685 if (workStealingQueue2._currentOp != 0)
686 {
687 SpinWait spinWait = default(SpinWait);
688 do
689 {
690 spinWait.SpinOnce();
691 }
692 while (workStealingQueue2._currentOp != 0);
693 }
694 }
695 }
696
697 private void UnfreezeBag(bool lockTaken)
698 {
699 if (!lockTaken)
700 {
701 return;
702 }
703 for (WorkStealingQueue workStealingQueue = _workStealingQueues; workStealingQueue != null; workStealingQueue = workStealingQueue._nextQueue)
704 {
705 if (workStealingQueue._frozen)
706 {
707 workStealingQueue._frozen = false;
708 Monitor.Exit(workStealingQueue);
709 }
710 }
712 }
713}
static unsafe void Clear(Array array)
Definition Array.cs:755
static unsafe void Copy(Array sourceArray, Array destinationArray, int length)
Definition Array.cs:624
void LocalPush(T item, ref long emptyToNonEmptyListTransitionCount)
bool TryLocalPop([MaybeNullWhen(false)] out T result)
bool TryLocalPeek([MaybeNullWhen(false)] out T result)
bool TrySteal([MaybeNullWhen(false)] out T result, bool take)
WorkStealingQueue CreateWorkStealingQueueForCurrentThread()
bool TryTake([MaybeNullWhen(false)] out T result)
WorkStealingQueue GetCurrentThreadWorkStealingQueue(bool forceCreate)
int CopyFromEachQueueToArray(T[] array, int index)
bool TryPeek([MaybeNullWhen(false)] out T result)
bool TryStealFromTo(WorkStealingQueue startInclusive, WorkStealingQueue endExclusive, [MaybeNullWhen(false)] out T result, bool take)
ConcurrentBag(IEnumerable< T > collection)
bool TrySteal([MaybeNullWhen(false)] out T result, bool take)
volatile WorkStealingQueue _workStealingQueues
readonly ThreadLocal< WorkStealingQueue > _locals
bool TryAdd(TKey key, TValue value)
static int CurrentManagedThreadId
static string ConcurrentBag_CopyTo_ArgumentNullException
Definition SR.cs:54
static string ConcurrentCollection_SyncRoot_NotSupported
Definition SR.cs:58
static string ConcurrentBag_Ctor_ArgumentNullException
Definition SR.cs:52
static string ConcurrentBag_Enumerator_EnumerationNotStartedOrAlreadyFinished
Definition SR.cs:92
static string Collection_CopyTo_TooManyElems
Definition SR.cs:32
static string Collection_CopyTo_ArgumentOutOfRangeException
Definition SR.cs:56
Definition SR.cs:7
static int Exchange(ref int location1, int value)
static long Read(ref long location)
static int Increment(ref int location)
static void Exit(object obj)
static void Enter(object obj)
void CopyTo(Array array, int index)