|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 using System; |
|
18 using System.Collections; |
|
19 using System.Collections.Generic; |
|
20 using System.Text; |
|
21 using System.Threading; |
|
22 |
|
23 namespace SymbianUtils.Threading |
|
24 { |
|
25 public class BlockingQueue<T> : ICollection, IEnumerable |
|
26 { |
|
27 #region Constructors |
|
28 public BlockingQueue() |
|
29 : this( -1 ) |
|
30 { |
|
31 } |
|
32 |
|
33 public BlockingQueue( int aMaxSize ) |
|
34 { |
|
35 iMaxSize = aMaxSize; |
|
36 iQueue = new Queue<T>(); |
|
37 } |
|
38 #endregion |
|
39 |
|
40 #region API |
|
41 public void Enqueue( T aItem ) |
|
42 { |
|
43 lock ( this.SyncRoot ) |
|
44 { |
|
45 // We want to prevent the queue from growing beyond it's own |
|
46 // bounds, unless the creator requested an unbounded queue. |
|
47 if ( iMaxSize > 0 ) |
|
48 { |
|
49 while ( this.Count >= iMaxSize ) |
|
50 { |
|
51 try |
|
52 { |
|
53 Monitor.Wait( this.SyncRoot ); |
|
54 } |
|
55 catch |
|
56 { |
|
57 Monitor.PulseAll( this.SyncRoot ); |
|
58 throw; |
|
59 } |
|
60 } |
|
61 } |
|
62 |
|
63 // Now it's okay to add the item |
|
64 iQueue.Enqueue( aItem ); |
|
65 |
|
66 // If the count is now one, then we've just added the first |
|
67 // item, in which case we must pulse the monitor because |
|
68 // there could be blocked threads that are stuck inside the Dequeue() |
|
69 // method, waiting for published content. |
|
70 int count = this.Count; |
|
71 if ( count == 1 ) |
|
72 { |
|
73 Monitor.PulseAll( this.SyncRoot ); |
|
74 } |
|
75 } |
|
76 } |
|
77 |
|
78 public bool TryToDequeue( out T aItem ) |
|
79 { |
|
80 bool ret = false; |
|
81 aItem = default( T ); |
|
82 // |
|
83 lock ( this.SyncRoot ) |
|
84 { |
|
85 if ( this.Count > 0 ) |
|
86 { |
|
87 aItem = iQueue.Dequeue(); |
|
88 ret = true; |
|
89 } |
|
90 } |
|
91 // |
|
92 return ret; |
|
93 } |
|
94 |
|
95 public void Clear() |
|
96 { |
|
97 lock ( this.SyncRoot ) |
|
98 { |
|
99 iQueue.Clear(); |
|
100 |
|
101 // Pulse, since clearing the items might allow a thread blocked |
|
102 // inside Enqueue() to push something to the head of the list |
|
103 Monitor.PulseAll( this.SyncRoot ); |
|
104 } |
|
105 } |
|
106 |
|
107 public T Dequeue() |
|
108 { |
|
109 lock ( this.SyncRoot ) |
|
110 { |
|
111 // Wait until the queue contains some content. |
|
112 while ( this.Count == 0 ) |
|
113 { |
|
114 try |
|
115 { |
|
116 Monitor.Wait( this.SyncRoot ); |
|
117 } |
|
118 catch |
|
119 { |
|
120 Monitor.PulseAll( this.SyncRoot ); |
|
121 throw; |
|
122 } |
|
123 } |
|
124 |
|
125 T ret = iQueue.Dequeue(); |
|
126 |
|
127 // We dequeue the item and then check to see if we have |
|
128 // just opened up the first free slot in the queue. |
|
129 // If so, we must pulse the monitor because there could be |
|
130 // threads blocked inside the Enqueue() method that are waiting |
|
131 // for space to become available. |
|
132 int count = this.Count; |
|
133 if ( iMaxSize > 0 && count == iMaxSize - 1 ) |
|
134 { |
|
135 Monitor.PulseAll( this.SyncRoot ); |
|
136 } |
|
137 // |
|
138 return ret; |
|
139 } |
|
140 } |
|
141 |
|
142 public T Peek() |
|
143 { |
|
144 lock ( this.SyncRoot ) |
|
145 { |
|
146 return iQueue.Peek(); |
|
147 } |
|
148 } |
|
149 |
|
150 public bool Contains( T aItem ) |
|
151 { |
|
152 lock ( this.SyncRoot ) |
|
153 { |
|
154 bool ret = iQueue.Contains( aItem ); |
|
155 return ret; |
|
156 } |
|
157 } |
|
158 |
|
159 public T[] ToArray() |
|
160 { |
|
161 lock ( this.SyncRoot ) |
|
162 { |
|
163 T[] ret = iQueue.ToArray(); |
|
164 return ret; |
|
165 } |
|
166 } |
|
167 #endregion |
|
168 |
|
169 #region From IEnumerable |
|
170 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
|
171 { |
|
172 throw new NotImplementedException( "You cannot enumerate a Blocking Queue - get the values and enumerate those instead" ); |
|
173 } |
|
174 #endregion |
|
175 |
|
176 #region From ICollection |
|
177 public void CopyTo( Array aArray, int aIndex ) |
|
178 { |
|
179 lock ( this.SyncRoot ) |
|
180 { |
|
181 ICollection baseCol = (ICollection) iQueue; |
|
182 baseCol.CopyTo( aArray, aIndex ); |
|
183 } |
|
184 } |
|
185 |
|
186 public int Count |
|
187 { |
|
188 get |
|
189 { |
|
190 lock ( this.SyncRoot ) |
|
191 { |
|
192 return iQueue.Count; |
|
193 } |
|
194 } |
|
195 } |
|
196 |
|
197 public bool IsSynchronized |
|
198 { |
|
199 get { return true; } |
|
200 } |
|
201 |
|
202 public object SyncRoot |
|
203 { |
|
204 get |
|
205 { |
|
206 if ( this.iSyncRoot == null ) |
|
207 { |
|
208 Interlocked.CompareExchange( ref this.iSyncRoot, new object(), null ); |
|
209 } |
|
210 return iSyncRoot; |
|
211 } |
|
212 } |
|
213 #endregion |
|
214 |
|
215 #region Data members |
|
216 private readonly Queue<T> iQueue; |
|
217 private object iSyncRoot = null; |
|
218 private readonly int iMaxSize; |
|
219 #endregion |
|
220 } |
|
221 } |