corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Collections.Generic;
29 using System.Threading;
30  
31 namespace OpenMetaverse
32 {
33 /// <summary>
34 /// Provides helper methods for parallelizing loops
35 /// </summary>
36 public static class Parallel
37 {
38 private static readonly int processorCount = System.Environment.ProcessorCount;
39  
40 /// <summary>
41 /// Executes a for loop in which iterations may run in parallel
42 /// </summary>
43 /// <param name="fromInclusive">The loop will be started at this index</param>
44 /// <param name="toExclusive">The loop will be terminated before this index is reached</param>
45 /// <param name="body">Method body to run for each iteration of the loop</param>
46 public static void For(int fromInclusive, int toExclusive, Action<int> body)
47 {
48 For(processorCount, fromInclusive, toExclusive, body);
49 }
50  
51 /// <summary>
52 /// Executes a for loop in which iterations may run in parallel
53 /// </summary>
54 /// <param name="threadCount">The number of concurrent execution threads to run</param>
55 /// <param name="fromInclusive">The loop will be started at this index</param>
56 /// <param name="toExclusive">The loop will be terminated before this index is reached</param>
57 /// <param name="body">Method body to run for each iteration of the loop</param>
58 public static void For(int threadCount, int fromInclusive, int toExclusive, Action<int> body)
59 {
60 int counter = threadCount;
61 AutoResetEvent threadFinishEvent = new AutoResetEvent(false);
62 Exception exception = null;
63  
64 --fromInclusive;
65  
66 for (int i = 0; i < threadCount; i++)
67 {
68 WorkPool.QueueUserWorkItem(
69 delegate(object o)
70 {
71 int threadIndex = (int)o;
72  
73 while (exception == null)
74 {
75 int currentIndex = Interlocked.Increment(ref fromInclusive);
76  
77 if (currentIndex >= toExclusive)
78 break;
79  
80 try { body(currentIndex); }
81 catch (Exception ex) { exception = ex; break; }
82 }
83  
84 if (Interlocked.Decrement(ref counter) == 0)
85 threadFinishEvent.Set();
86 }, i
87 );
88 }
89  
90 threadFinishEvent.WaitOne();
91  
92 if (exception != null)
93 throw exception;
94 }
95  
96 /// <summary>
97 /// Executes a foreach loop in which iterations may run in parallel
98 /// </summary>
99 /// <typeparam name="T">Object type that the collection wraps</typeparam>
100 /// <param name="enumerable">An enumerable collection to iterate over</param>
101 /// <param name="body">Method body to run for each object in the collection</param>
102 public static void ForEach<T>(IEnumerable<T> enumerable, Action<T> body)
103 {
104 ForEach<T>(processorCount, enumerable, body);
105 }
106  
107 /// <summary>
108 /// Executes a foreach loop in which iterations may run in parallel
109 /// </summary>
110 /// <typeparam name="T">Object type that the collection wraps</typeparam>
111 /// <param name="threadCount">The number of concurrent execution threads to run</param>
112 /// <param name="enumerable">An enumerable collection to iterate over</param>
113 /// <param name="body">Method body to run for each object in the collection</param>
114 public static void ForEach<T>(int threadCount, IEnumerable<T> enumerable, Action<T> body)
115 {
116 int counter = threadCount;
117 AutoResetEvent threadFinishEvent = new AutoResetEvent(false);
118 IEnumerator<T> enumerator = enumerable.GetEnumerator();
119 Exception exception = null;
120  
121 for (int i = 0; i < threadCount; i++)
122 {
123 WorkPool.QueueUserWorkItem(
124 delegate(object o)
125 {
126 int threadIndex = (int)o;
127  
128 while (exception == null)
129 {
130 T entry;
131  
132 lock (enumerator)
133 {
134 if (!enumerator.MoveNext())
135 break;
136 entry = (T)enumerator.Current; // Explicit typecast for Mono's sake
137 }
138  
139 try { body(entry); }
140 catch (Exception ex) { exception = ex; break; }
141 }
142  
143 if (Interlocked.Decrement(ref counter) == 0)
144 threadFinishEvent.Set();
145 }, i
146 );
147 }
148  
149 threadFinishEvent.WaitOne();
150  
151 if (exception != null)
152 throw exception;
153 }
154  
155 /// <summary>
156 /// Executes a series of tasks in parallel
157 /// </summary>
158 /// <param name="actions">A series of method bodies to execute</param>
159 public static void Invoke(params Action[] actions)
160 {
161 Invoke(processorCount, actions);
162 }
163  
164 /// <summary>
165 /// Executes a series of tasks in parallel
166 /// </summary>
167 /// <param name="threadCount">The number of concurrent execution threads to run</param>
168 /// <param name="actions">A series of method bodies to execute</param>
169 public static void Invoke(int threadCount, params Action[] actions)
170 {
171 int counter = threadCount;
172 AutoResetEvent threadFinishEvent = new AutoResetEvent(false);
173 int index = -1;
174 Exception exception = null;
175  
176 for (int i = 0; i < threadCount; i++)
177 {
178 WorkPool.QueueUserWorkItem(
179 delegate(object o)
180 {
181 int threadIndex = (int)o;
182  
183 while (exception == null)
184 {
185 int currentIndex = Interlocked.Increment(ref index);
186  
187 if (currentIndex >= actions.Length)
188 break;
189  
190 try { actions[currentIndex](); }
191 catch (Exception ex) { exception = ex; break; }
192 }
193  
194 if (Interlocked.Decrement(ref counter) == 0)
195 threadFinishEvent.Set();
196 }, i
197 );
198 }
199  
200 threadFinishEvent.WaitOne();
201  
202 if (exception != null)
203 throw exception;
204 }
205 }
206 }