6 // Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
8 // Copyright (c) 2009 Jérémie "Garuma" Laval
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 using System
.Collections
;
30 using System
.Collections
.Generic
;
32 using System
.Threading
;
33 using System
.Threading
.Tasks
;
35 namespace System
.Collections
.Concurrent
38 public class ConcurrentBag
<T
> : IProducerConsumerCollection
<T
>, IEnumerable
<T
>, IEnumerable
40 int size
= Environment
.ProcessorCount
+ 1;
44 CyclicDeque
<T
>[] container
;
46 object syncLock
= new object ();
48 public ConcurrentBag ()
50 container
= new CyclicDeque
<T
>[size
];
51 for (int i
= 0; i
< container
.Length
; i
++)
52 container
[i
] = new CyclicDeque
<T
> ();
55 public ConcurrentBag (IEnumerable
<T
> enumerable
) : this ()
57 foreach (T item
in enumerable
)
61 public bool TryAdd (T item
)
68 public void Add (T item
)
70 Interlocked
.Increment (ref count
);
73 CyclicDeque
<T
> bag
= GetBag ();
74 bag
.PushBottom (item
);
77 public bool TryTake (out T item
)
80 CyclicDeque
<T
> bag
= GetBag ();
82 if (bag
== null || bag
.PopBottom (out item
) != PopResult
.Succeed
) {
83 for (int i
= 0; i
< container
.Length
; i
++) {
84 if (container
[i
].PopTop (out item
) == PopResult
.Succeed
) {
85 Interlocked
.Decrement (ref count
);
90 Interlocked
.Decrement (ref count
);
103 public bool IsEmpty
{
109 public object SyncRoot
{
115 public bool IsSynchronized
{
121 IEnumerator IEnumerable
.GetEnumerator ()
123 return GetEnumeratorInternal ();
126 IEnumerator
<T
> IEnumerable
<T
>.GetEnumerator ()
128 return GetEnumeratorInternal ();
131 IEnumerator
<T
> GetEnumeratorInternal ()
133 for (int i
= 0; i
< size
; i
++) {
134 CyclicDeque
<T
> bag
= container
[i
];
135 foreach (T item
in bag
.GetEnumerable ()) {
141 public void CopyTo (Array array
, int index
)
143 T
[] a
= array
as T
[];
150 public void CopyTo (T
[] array
, int index
)
153 if (array
.Length
< c
+ index
)
154 throw new InvalidOperationException ("Array is not big enough");
156 CopyTo (array
, index
, c
);
159 void CopyTo (T
[] array
, int index
, int num
)
163 foreach (T item
in this) {
171 public T
[] ToArray ()
183 return Thread
.CurrentThread
.ManagedThreadId
- 1;
186 void GrowIfNecessary ()
188 int index
= GetIndex ();
189 int currentSize
= size
;
191 while (index
> currentSize
- 1) {
197 CyclicDeque
<T
> GetBag ()
201 return i
< container
.Length
? container
[i
] : null;
204 void Grow (int referenceSize
)
207 if (referenceSize
!= size
)
210 CyclicDeque
<T
>[] slice
= new CyclicDeque
<T
>[size
* multiplier
];
212 for (i
= 0; i
< container
.Length
; i
++)
213 slice
[i
] = container
[i
];
214 for (; i
< slice
.Length
; i
++)
215 slice
[i
] = new CyclicDeque
<T
> ();