diff --git a/src/FSharpExamples/Apply.fs b/src/FSharpExamples/Apply.fs index dc2c675b..b99e8a2a 100644 --- a/src/FSharpExamples/Apply.fs +++ b/src/FSharpExamples/Apply.fs @@ -27,6 +27,7 @@ // module MathNet.Numerics.FSharp.Examples.Apply +open System.Numerics open MathNet.Numerics open MathNet.Numerics.LinearAlgebra.Double diff --git a/src/FSharpExamples/FSharpExamples.fsproj b/src/FSharpExamples/FSharpExamples.fsproj index f91e2310..6b257ead 100644 --- a/src/FSharpExamples/FSharpExamples.fsproj +++ b/src/FSharpExamples/FSharpExamples.fsproj @@ -37,6 +37,7 @@ 3.5 + diff --git a/src/MathNet.Numerics.sln b/src/MathNet.Numerics.sln index f14a0f50..42db81f8 100644 --- a/src/MathNet.Numerics.sln +++ b/src/MathNet.Numerics.sln @@ -13,7 +13,7 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpExamples", "FSharpExa EndProject Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FSharpUnitTests", "FSharpUnitTests\FSharpUnitTests.fsproj", "{F2F8032B-A31D-4E33-A05E-F2CDCBFAA75D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silverlight", "Silverlight\Silverlight.csproj", "{0CCA2BA4-9DF2-4E9B-8A77-0A1F61A96A77}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Silverlight", "Silverlight\Silverlight.csproj", "{793E332F-E2B1-4D1D-9B2E-27E90B99BF93}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -45,10 +45,10 @@ Global {F2F8032B-A31D-4E33-A05E-F2CDCBFAA75D}.Debug|Any CPU.Build.0 = Debug|Any CPU {F2F8032B-A31D-4E33-A05E-F2CDCBFAA75D}.Release|Any CPU.ActiveCfg = Release|Any CPU {F2F8032B-A31D-4E33-A05E-F2CDCBFAA75D}.Release|Any CPU.Build.0 = Release|Any CPU - {0CCA2BA4-9DF2-4E9B-8A77-0A1F61A96A77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0CCA2BA4-9DF2-4E9B-8A77-0A1F61A96A77}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0CCA2BA4-9DF2-4E9B-8A77-0A1F61A96A77}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0CCA2BA4-9DF2-4E9B-8A77-0A1F61A96A77}.Release|Any CPU.Build.0 = Release|Any CPU + {793E332F-E2B1-4D1D-9B2E-27E90B99BF93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {793E332F-E2B1-4D1D-9B2E-27E90B99BF93}.Debug|Any CPU.Build.0 = Debug|Any CPU + {793E332F-E2B1-4D1D-9B2E-27E90B99BF93}.Release|Any CPU.ActiveCfg = Release|Any CPU + {793E332F-E2B1-4D1D-9B2E-27E90B99BF93}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs index f29344f3..7c8e7212 100644 --- a/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs +++ b/src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs @@ -24,10 +24,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { using System; - using System.Collections.Concurrent; using System.Numerics; - using System.Threading.Tasks; using Properties; + using Threading; /// /// The managed linear algebra provider. @@ -67,27 +66,13 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha == 1.0) { - Parallel.ForEach( - Partitioner.Create(0, y.Length), - (range, loopState) => - { - for (var i = range.Item1; i < range.Item2; i++) - { - y[i] += x[i]; - } - }); + CommonParallel.For(0, y.Length, + index => { y[index] += x[index]; }); } else { - Parallel.ForEach( - Partitioner.Create(0, y.Length), - (range, loopState) => - { - for (var i = range.Item1; i < range.Item2; i++) - { - y[i] += alpha * x[i]; - } - }); + CommonParallel.For(0, y.Length, + index => { y[index] += alpha * x[index]; }); } } @@ -109,15 +94,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra return; } - Parallel.ForEach( - Partitioner.Create(0, x.Length), - (range, loopState) => - { - for (var i = range.Item1; i < range.Item2; i++) - { - x[i] = alpha * x[i]; - } - }); + CommonParallel.For(0, x.Length, + index => { x[index] = alpha * x[index]; }); } /// @@ -144,30 +122,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - var sync = new object(); - var d = 0.0; - - Parallel.ForEach( - Partitioner.Create(0, y.Length), - () => 0.0, - (range, loopState, localData) => - { - for (var i = range.Item1; i < range.Item2; i++) - { - localData += y[i] * x[i]; - } - - return localData; - }, - localResult => - { - lock (sync) - { - d += localResult; - } - }); - - return d; + return CommonParallel.Aggregate(0, y.Length, index => y[index] * x[index]); } /// @@ -202,15 +157,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - Parallel.ForEach( - Partitioner.Create(0, y.Length), - (range, loopState) => - { - for (var i = range.Item1; i < range.Item2; i++) - { - result[i] = x[i] + y[i]; - } - }); + CommonParallel.For(0, y.Length, index => { result[index] = x[index] + y[index]; }); } /// @@ -245,15 +192,8 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - Parallel.ForEach( - Partitioner.Create(0, y.Length), - (range, loopState) => - { - for (var i = range.Item1; i < range.Item2; i++) - { - result[i] = x[i] - y[i]; - } - }); + CommonParallel.For(0, y.Length, + index => { result[index] = x[index] - y[index]; }); } /// @@ -287,16 +227,9 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - - Parallel.ForEach( - Partitioner.Create(0, y.Length), - (range, loopState) => - { - for (var i = range.Item1; i < range.Item2; i++) - { - result[i] = x[i] * y[i]; - } - }); + + CommonParallel.For(0, y.Length, + index => { result[index] = x[index] * y[index]; }); } public double MatrixNorm(Norm norm, double[] matrix) @@ -513,190 +446,158 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.ForEach( - Partitioner.Create(0, aColumns), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jIndex = j * cRows; - for (var i = 0; i != bRows; i++) - { - var iIndex = i * aRows; - double s = 0; - for (var l = 0; l != bColumns; l++) - { - s += adata[iIndex + l] * bdata[l * bRows + j]; - } - - c[jIndex + i] = s; - } - } - }); + CommonParallel.For(0, aColumns, + j => + { + var jIndex = j * cRows; + for (var i = 0; i != bRows; i++) + { + var iIndex = i * aRows; + double s = 0; + for (var l = 0; l != bColumns; l++) + { + s += adata[iIndex + l] * bdata[l * bRows + j]; + } + + c[jIndex + i] = s; + } + }); } else if ((int)transposeA > 111) { - Parallel.ForEach( - Partitioner.Create(0, bColumns), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jcIndex = j * cRows; - var jbIndex = j * bRows; - for (var i = 0; i != aColumns; i++) - { - var iIndex = i * aRows; - double s = 0; - for (var l = 0; l != aRows; l++) - { - s += adata[iIndex + l] * bdata[jbIndex + l]; - } - - c[jcIndex + i] = s; - } - } - }); + CommonParallel.For(0, bColumns, + j => + { + var jcIndex = j * cRows; + var jbIndex = j * bRows; + for (var i = 0; i != aColumns; i++) + { + var iIndex = i * aRows; + double s = 0; + for (var l = 0; l != aRows; l++) + { + s += adata[iIndex + l] * bdata[jbIndex + l]; + } + + c[jcIndex + i] = s; + } + }); } else if ((int)transposeB > 111) { - Parallel.ForEach( - Partitioner.Create(0, bRows), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jIndex = j * cRows; - for (var i = 0; i != aRows; i++) - { - double s = 0; - for (var l = 0; l != aColumns; l++) - { - s += adata[l * aRows + i] * bdata[l * bRows + j]; - } - - c[jIndex + i] = s; - } - } - }); + CommonParallel.For(0, bRows, + j => + { + var jIndex = j * cRows; + for (var i = 0; i != aRows; i++) + { + double s = 0; + for (var l = 0; l != aColumns; l++) + { + s += adata[l * aRows + i] * bdata[l * bRows + j]; + } + + c[jIndex + i] = s; + } + }); } else { - Parallel.ForEach( - Partitioner.Create(0, bColumns), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jcIndex = j * cRows; - var jbIndex = j * bRows; - for (var i = 0; i != aRows; i++) - { - double s = 0; - for (var l = 0; l != aColumns; l++) - { - s += adata[l * aRows + i] * bdata[jbIndex + l]; - } - - c[jcIndex + i] = s; - } - } - }); + CommonParallel.For(0, bColumns, + j => + { + var jcIndex = j * cRows; + var jbIndex = j * bRows; + for (var i = 0; i != aRows; i++) + { + double s = 0; + for (var l = 0; l != aColumns; l++) + { + s += adata[l * aRows + i] * bdata[jbIndex + l]; + } + + c[jcIndex + i] = s; + } + }); } } else { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.ForEach( - Partitioner.Create(0, aColumns), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jIndex = j * cRows; - for (var i = 0; i != bRows; i++) - { - var iIndex = i * aRows; - double s = 0; - for (var l = 0; l != bColumns; l++) - { - s += adata[iIndex + l] * bdata[l * bRows + j]; - } - - c[jIndex + i] = c[jIndex + i] * beta + s; - } - } - }); + CommonParallel.For(0, aColumns, + j => + { + var jIndex = j * cRows; + for (var i = 0; i != bRows; i++) + { + var iIndex = i * aRows; + double s = 0; + for (var l = 0; l != bColumns; l++) + { + s += adata[iIndex + l] * bdata[l * bRows + j]; + } + + c[jIndex + i] = c[jIndex + i] * beta + s; + } + }); } else if ((int)transposeA > 111) { - Parallel.ForEach( - Partitioner.Create(0, bColumns), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jcIndex = j * cRows; - var jbIndex = j * bRows; - for (var i = 0; i != aColumns; i++) - { - var iIndex = i * aRows; - double s = 0; - for (var l = 0; l != aRows; l++) - { - s += adata[iIndex + l] * bdata[jbIndex + l]; - } - - c[jcIndex + i] = s + c[jcIndex + i] * beta; - } - } - }); + CommonParallel.For(0, bColumns, + j => + { + var jcIndex = j * cRows; + var jbIndex = j * bRows; + for (var i = 0; i != aColumns; i++) + { + var iIndex = i * aRows; + double s = 0; + for (var l = 0; l != aRows; l++) + { + s += adata[iIndex + l] * bdata[jbIndex + l]; + } + + c[jcIndex + i] = s + c[jcIndex + i] * beta; + } + }); } else if ((int)transposeB > 111) { - Parallel.ForEach( - Partitioner.Create(0, bRows), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jIndex = j * cRows; - for (var i = 0; i != aRows; i++) - { - double s = 0; - for (var l = 0; l != aColumns; l++) - { - s += adata[l * aRows + i] * bdata[l * bRows + j]; - } - - c[jIndex + i] = s + c[jIndex + i] * beta; - } - } - }); + CommonParallel.For(0, bRows, + j => + { + var jIndex = j * cRows; + for (var i = 0; i != aRows; i++) + { + double s = 0; + for (var l = 0; l != aColumns; l++) + { + s += adata[l * aRows + i] * bdata[l * bRows + j]; + } + + c[jIndex + i] = s + c[jIndex + i] * beta; + } + }); } else { - Parallel.ForEach( - Partitioner.Create(0, bColumns), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jcIndex = j * cRows; - var jbIndex = j * bRows; - for (var i = 0; i != aRows; i++) - { - double s = 0; - for (var l = 0; l != aColumns; l++) - { - s += adata[l * aRows + i] * bdata[jbIndex + l]; - } - - c[jcIndex + i] = s + c[jcIndex + i] * beta; - } - } - }); + CommonParallel.For(0, bColumns, + j => + { + var jcIndex = j * cRows; + var jbIndex = j * bRows; + for (var i = 0; i != aRows; i++) + { + double s = 0; + for (var l = 0; l != aColumns; l++) + { + s += adata[l * aRows + i] * bdata[jbIndex + l]; + } + + c[jcIndex + i] = s + c[jcIndex + i] * beta; + } + }); } } } @@ -704,95 +605,79 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.ForEach( - Partitioner.Create(0, aColumns), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jIndex = j * cRows; - for (var i = 0; i != bRows; i++) - { - var iIndex = i * aRows; - double s = 0; - for (var l = 0; l != bColumns; l++) - { - s += adata[iIndex + l] * bdata[l * bRows + j]; - } - - c[jIndex + i] = c[jIndex + i] * beta + alpha * s; - } - } - }); + CommonParallel.For(0, aColumns, + j => + { + var jIndex = j * cRows; + for (var i = 0; i != bRows; i++) + { + var iIndex = i * aRows; + double s = 0; + for (var l = 0; l != bColumns; l++) + { + s += adata[iIndex + l] * bdata[l * bRows + j]; + } + + c[jIndex + i] = c[jIndex + i] * beta + alpha * s; + } + }); } else if ((int)transposeA > 111) { - Parallel.ForEach( - Partitioner.Create(0, bColumns), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jcIndex = j * cRows; - var jbIndex = j * bRows; - for (var i = 0; i != aColumns; i++) - { - var iIndex = i * aRows; - double s = 0; - for (var l = 0; l != aRows; l++) - { - s += adata[iIndex + l] * bdata[jbIndex + l]; - } - - c[jcIndex + i] = alpha * s + c[jcIndex + i] * beta; - } - } - }); + CommonParallel.For(0, bColumns, + j => + { + var jcIndex = j * cRows; + var jbIndex = j * bRows; + for (var i = 0; i != aColumns; i++) + { + var iIndex = i * aRows; + double s = 0; + for (var l = 0; l != aRows; l++) + { + s += adata[iIndex + l] * bdata[jbIndex + l]; + } + + c[jcIndex + i] = alpha * s + c[jcIndex + i] * beta; + } + }); } else if ((int)transposeB > 111) { - Parallel.ForEach( - Partitioner.Create(0, bRows), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jIndex = j * cRows; - for (var i = 0; i != aRows; i++) - { - double s = 0; - for (var l = 0; l != aColumns; l++) - { - s += adata[l * aRows + i] * bdata[l * bRows + j]; - } - - c[jIndex + i] = alpha * s + c[jIndex + i] * beta; - } - } - }); + CommonParallel.For(0, bRows, + j => + { + var jIndex = j * cRows; + for (var i = 0; i != aRows; i++) + { + double s = 0; + for (var l = 0; l != aColumns; l++) + { + s += adata[l * aRows + i] * bdata[l * bRows + j]; + } + + c[jIndex + i] = alpha * s + c[jIndex + i] * beta; + } + }); } else { - Parallel.ForEach( - Partitioner.Create(0, bColumns), - (range, loopState) => - { - for (var j = range.Item1; j < range.Item2; j++) - { - var jcIndex = j * cRows; - var jbIndex = j * bRows; - for (var i = 0; i != aRows; i++) - { - double s = 0; - for (var l = 0; l != aColumns; l++) - { - s += adata[l * aRows + i] * bdata[jbIndex + l]; - } - - c[jcIndex + i] = alpha * s + c[jcIndex + i] * beta; - } - } - }); + CommonParallel.For(0, bColumns, + j => + { + var jcIndex = j * cRows; + var jbIndex = j * bRows; + for (var i = 0; i != aRows; i++) + { + double s = 0; + for (var l = 0; l != aColumns; l++) + { + s += adata[l * aRows + i] * bdata[jbIndex + l]; + } + + c[jcIndex + i] = alpha * s + c[jcIndex + i] * beta; + } + }); } } } @@ -980,11 +865,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha == 1.0) { - Parallel.For(0, y.Length, i => y[i] += x[i]); + CommonParallel.For(0, y.Length, i => y[i] += x[i]); } else { - Parallel.For(0, y.Length, i => y[i] += alpha * x[i]); + CommonParallel.For(0, y.Length, i => y[i] += alpha * x[i]); } } @@ -1006,7 +891,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra return; } - Parallel.For(0, x.Length, i => x[i] = alpha * x[i]); + CommonParallel.For(0, x.Length, i => x[i] = alpha * x[i]); } /// @@ -1075,7 +960,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - Parallel.For(0, y.Length, i => result[i] = x[i] + y[i]); + CommonParallel.For(0, y.Length, i => result[i] = x[i] + y[i]); } /// @@ -1110,7 +995,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - Parallel.For(0, y.Length, i => result[i] = x[i] - y[i]); + CommonParallel.For(0, y.Length, i => result[i] = x[i] - y[i]); } /// @@ -1145,7 +1030,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - Parallel.For(0, y.Length, i => result[i] = x[i] * y[i]); + CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]); } public float MatrixNorm(Norm norm, float[] matrix) @@ -1368,7 +1253,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.For(0, aColumns, j => + CommonParallel.For(0, aColumns, j => { var jIndex = j * cRows; for (var i = 0; i != bRows; i++) @@ -1386,7 +1271,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeA > 111) { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -1405,7 +1290,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeB > 111) { - Parallel.For(0, bRows, j => + CommonParallel.For(0, bRows, j => { var jIndex = j * cRows; for (var i = 0; i != aRows; i++) @@ -1422,7 +1307,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -1443,7 +1328,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.For(0, aColumns, j => + CommonParallel.For(0, aColumns, j => { var jIndex = j * cRows; for (var i = 0; i != bRows; i++) @@ -1461,7 +1346,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeA > 111) { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -1480,7 +1365,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeB > 111) { - Parallel.For(0, bRows, j => + CommonParallel.For(0, bRows, j => { var jIndex = j * cRows; for (var i = 0; i != aRows; i++) @@ -1497,7 +1382,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -1519,7 +1404,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.For(0, aColumns, j => + CommonParallel.For(0, aColumns, j => { var jIndex = j * cRows; for (var i = 0; i != bRows; i++) @@ -1537,7 +1422,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeA > 111) { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -1556,7 +1441,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeB > 111) { - Parallel.For(0, bRows, j => + CommonParallel.For(0, bRows, j => { var jIndex = j * cRows; for (var i = 0; i != aRows; i++) @@ -1573,7 +1458,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -1779,11 +1664,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha == 1.0) { - Parallel.For(0, y.Length, i => y[i] += x[i]); + CommonParallel.For(0, y.Length, i => y[i] += x[i]); } else { - Parallel.For(0, y.Length, i => y[i] += alpha * x[i]); + CommonParallel.For(0, y.Length, i => y[i] += alpha * x[i]); } } @@ -1805,7 +1690,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra return; } - Parallel.For(0, x.Length, i => x[i] = alpha * x[i]); + CommonParallel.For(0, x.Length, i => x[i] = alpha * x[i]); } /// @@ -1874,7 +1759,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - Parallel.For(0, y.Length, i => result[i] = x[i] + y[i]); + CommonParallel.For(0, y.Length, i => result[i] = x[i] + y[i]); } /// @@ -1909,7 +1794,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - Parallel.For(0, y.Length, i => result[i] = x[i] - y[i]); + CommonParallel.For(0, y.Length, i => result[i] = x[i] - y[i]); } /// @@ -1944,7 +1829,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - Parallel.For(0, y.Length, i => result[i] = x[i] * y[i]); + CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]); } public Complex MatrixNorm(Norm norm, Complex[] matrix) @@ -2167,7 +2052,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.For(0, aColumns, j => + CommonParallel.For(0, aColumns, j => { var jIndex = j * cRows; for (var i = 0; i != bRows; i++) @@ -2185,7 +2070,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeA > 111) { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -2204,7 +2089,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeB > 111) { - Parallel.For(0, bRows, j => + CommonParallel.For(0, bRows, j => { var jIndex = j * cRows; for (var i = 0; i != aRows; i++) @@ -2221,7 +2106,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -2242,7 +2127,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.For(0, aColumns, j => + CommonParallel.For(0, aColumns, j => { var jIndex = j * cRows; for (var i = 0; i != bRows; i++) @@ -2260,7 +2145,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeA > 111) { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -2279,7 +2164,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeB > 111) { - Parallel.For(0, bRows, j => + CommonParallel.For(0, bRows, j => { var jIndex = j * cRows; for (var i = 0; i != aRows; i++) @@ -2296,7 +2181,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -2318,7 +2203,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.For(0, aColumns, j => + CommonParallel.For(0, aColumns, j => { var jIndex = j * cRows; for (var i = 0; i != bRows; i++) @@ -2336,7 +2221,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeA > 111) { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -2355,7 +2240,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeB > 111) { - Parallel.For(0, bRows, j => + CommonParallel.For(0, bRows, j => { var jIndex = j * cRows; for (var i = 0; i != aRows; i++) @@ -2372,7 +2257,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -2543,11 +2428,11 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra if (alpha == 1.0F) { - Parallel.For(0, y.Length, i => y[i] += x[i]); + CommonParallel.For(0, y.Length, i => y[i] += x[i]); } else { - Parallel.For(0, y.Length, i => y[i] += alpha * x[i]); + CommonParallel.For(0, y.Length, i => y[i] += alpha * x[i]); } } @@ -2569,7 +2454,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra return; } - Parallel.For(0, x.Length, i => x[i] = alpha * x[i]); + CommonParallel.For(0, x.Length, i => x[i] = alpha * x[i]); } /// @@ -2638,7 +2523,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - Parallel.For(0, y.Length, i => result[i] = x[i] + y[i]); + CommonParallel.For(0, y.Length, i => result[i] = x[i] + y[i]); } /// @@ -2673,7 +2558,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - Parallel.For(0, y.Length, i => result[i] = x[i] - y[i]); + CommonParallel.For(0, y.Length, i => result[i] = x[i] - y[i]); } /// @@ -2708,7 +2593,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra throw new ArgumentException(Resources.ArgumentVectorsSameLength); } - Parallel.For(0, y.Length, i => result[i] = x[i] * y[i]); + CommonParallel.For(0, y.Length, i => result[i] = x[i] * y[i]); } public Complex32 MatrixNorm(Norm norm, Complex32[] matrix) @@ -2931,7 +2816,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.For(0, aColumns, j => + CommonParallel.For(0, aColumns, j => { var jIndex = j * cRows; for (var i = 0; i != bRows; i++) @@ -2949,7 +2834,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeA > 111) { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -2968,7 +2853,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeB > 111) { - Parallel.For(0, bRows, j => + CommonParallel.For(0, bRows, j => { var jIndex = j * cRows; for (var i = 0; i != aRows; i++) @@ -2985,7 +2870,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -3006,7 +2891,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.For(0, aColumns, j => + CommonParallel.For(0, aColumns, j => { var jIndex = j * cRows; for (var i = 0; i != bRows; i++) @@ -3024,7 +2909,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeA > 111) { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -3043,7 +2928,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeB > 111) { - Parallel.For(0, bRows, j => + CommonParallel.For(0, bRows, j => { var jIndex = j * cRows; for (var i = 0; i != aRows; i++) @@ -3060,7 +2945,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -3082,7 +2967,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra { if ((int)transposeA > 111 && (int)transposeB > 111) { - Parallel.For(0, aColumns, j => + CommonParallel.For(0, aColumns, j => { var jIndex = j * cRows; for (var i = 0; i != bRows; i++) @@ -3100,7 +2985,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeA > 111) { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; @@ -3119,7 +3004,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else if ((int)transposeB > 111) { - Parallel.For(0, bRows, j => + CommonParallel.For(0, bRows, j => { var jIndex = j * cRows; for (var i = 0; i != aRows; i++) @@ -3136,7 +3021,7 @@ namespace MathNet.Numerics.Algorithms.LinearAlgebra } else { - Parallel.For(0, bColumns, j => + CommonParallel.For(0, bColumns, j => { var jcIndex = j * cRows; var jbIndex = j * bRows; diff --git a/src/Numerics/Control.cs b/src/Numerics/Control.cs index 15381230..4d3ee43d 100644 --- a/src/Numerics/Control.cs +++ b/src/Numerics/Control.cs @@ -28,6 +28,7 @@ namespace MathNet.Numerics { + using System; using Algorithms.LinearAlgebra; /// @@ -35,6 +36,13 @@ namespace MathNet.Numerics /// public static class Control { +#if !SILVERLIGHT + /// + /// Initial number of threads to use; + /// + private static int _numberOfThreads = Environment.ProcessorCount; +#endif + /// /// Initializes static members of the Control class. /// @@ -75,5 +83,28 @@ namespace MathNet.Numerics { get; set; } + + /// + /// Gets or sets a value indicating how many parallel worker threads shall be used + /// when parallelization is applicable. + /// + /// The Silverlight version of the library defaults to one thread. + public static int NumberOfParallelWorkerThreads + { +#if SILVERLIGHT + get { return ThreadQueue.ThreadCount; } + set { ThreadQueue.Start(value); } +#else + get + { + return _numberOfThreads; + } + + set + { // instead of throwing an out of range exception, simply normalize + _numberOfThreads = Math.Max(1, Math.Min(1024, value)); + } +#endif + } } } diff --git a/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.Bluestein.cs b/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.Bluestein.cs index 825ba0eb..45fda59d 100644 --- a/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.Bluestein.cs +++ b/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.Bluestein.cs @@ -30,9 +30,9 @@ namespace MathNet.Numerics.IntegralTransforms.Algorithms { using System; using System.Numerics; - using System.Threading.Tasks; using NumberTheory; - + using Threading; + /// /// Complex Fast (FFT) Implementation of the Discrete Fourier Transform (DFT). /// @@ -71,7 +71,7 @@ namespace MathNet.Numerics.IntegralTransforms.Algorithms Complex[] b = new Complex[m]; Complex[] a = new Complex[m]; - Parallel.Invoke( + CommonParallel.Invoke( () => { // Build and transform padded sequence b_k = exp(I*Pi*k^2/N) diff --git a/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.Naive.cs b/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.Naive.cs index cf9aadf9..dd8466c8 100644 --- a/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.Naive.cs +++ b/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.Naive.cs @@ -25,9 +25,8 @@ namespace MathNet.Numerics.IntegralTransforms.Algorithms { using System; - using System.Collections.Concurrent; using System.Numerics; - using System.Threading.Tasks; + using Threading; /// /// Complex Fast (FFT) Implementation of the Discrete Fourier Transform (DFT). @@ -45,23 +44,21 @@ namespace MathNet.Numerics.IntegralTransforms.Algorithms var w0 = exponentSign * Constants.Pi2 / samples.Length; var spectrum = new Complex[samples.Length]; - Parallel.ForEach( - Partitioner.Create(0, samples.Length), - (range, loopState) => - { - for (var k = range.Item1; k < range.Item2; k++) - { - var wk = w0 * k; - var sum = Complex.Zero; - for (var n = 0; n < samples.Length; n++) - { - var w = n * wk; - sum += samples[n] * new Complex(Math.Cos(w), Math.Sin(w)); - } + CommonParallel.For( + 0, + samples.Length, + index => + { + var wk = w0 * index; + var sum = Complex.Zero; + for (var n = 0; n < samples.Length; n++) + { + var w = n * wk; + sum += samples[n] * new Complex(Math.Cos(w), Math.Sin(w)); + } - spectrum[k] = sum; - } - }); + spectrum[index] = sum; + }); return spectrum; } diff --git a/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.RadixN.cs b/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.RadixN.cs index 76107de1..7644a27c 100644 --- a/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.RadixN.cs +++ b/src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.RadixN.cs @@ -25,11 +25,10 @@ namespace MathNet.Numerics.IntegralTransforms.Algorithms { using System; - using System.Collections.Concurrent; using System.Numerics; - using System.Threading.Tasks; using NumberTheory; using Properties; + using Threading; /// /// Complex Fast (FFT) Implementation of the Discrete Fourier Transform (DFT). @@ -127,15 +126,11 @@ namespace MathNet.Numerics.IntegralTransforms.Algorithms for (var levelSize = 1; levelSize < samples.Length; levelSize *= 2) { var size = levelSize; - Parallel.ForEach( - Partitioner.Create(0, size), - (range, loopState) => - { - for (var k = range.Item1; k < range.Item2; k++) - { - Radix2Step(samples, exponentSign, size, k); - } - }); + + CommonParallel.For( + 0, + size, + index => Radix2Step(samples, exponentSign, size, index)); } } diff --git a/src/Numerics/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Naive.cs b/src/Numerics/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Naive.cs index 2b079062..d48c29d0 100644 --- a/src/Numerics/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Naive.cs +++ b/src/Numerics/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Naive.cs @@ -25,8 +25,7 @@ namespace MathNet.Numerics.IntegralTransforms.Algorithms { using System; - using System.Collections.Concurrent; - using System.Threading.Tasks; + using Threading; /// /// Fast (FHT) Implementation of the Discrete Hartley Transform (DHT). @@ -43,22 +42,20 @@ namespace MathNet.Numerics.IntegralTransforms.Algorithms var w0 = Constants.Pi2 / samples.Length; var spectrum = new double[samples.Length]; - Parallel.ForEach( - Partitioner.Create(0, samples.Length), - (range, loopState) => + CommonParallel.For( + 0, + samples.Length, + index => { - for (var k = range.Item1; k < range.Item2; k++) + var wk = w0 * index; + var sum = 0.0; + for (var n = 0; n < samples.Length; n++) { - var wk = w0 * k; - var sum = 0.0; - for (var n = 0; n < samples.Length; n++) - { - var w = n * wk; - sum += samples[n] * Constants.Sqrt2 * Math.Cos(w - Constants.PiOver4); - } - - spectrum[k] = sum; + var w = n * wk; + sum += samples[n] * Constants.Sqrt2 * Math.Cos(w - Constants.PiOver4); } + + spectrum[index] = sum; }); return spectrum; diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 4e20e60e..9d335228 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -180,6 +180,7 @@ + diff --git a/src/Numerics/Threading/CommonParallel.cs b/src/Numerics/Threading/CommonParallel.cs new file mode 100644 index 00000000..dba3eae9 --- /dev/null +++ b/src/Numerics/Threading/CommonParallel.cs @@ -0,0 +1,147 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// Copyright (c) 2009-2010 Math.NET +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.Threading +{ + using System; + +#if !SILVERLIGHT + using System.Collections.Concurrent; + using System.Threading.Tasks; +#endif + + /// + /// Used to simplify parallel code, particularly between the .NET 4.0 and Silverlight Code. + /// + internal static class CommonParallel + { + /// + /// Executes a for loop in which iterations may run in parallel. + /// + /// The start index, inclusive. + /// The end index, exclusive. + /// The body to be invoked for each iteration. + /// The argument is null. + /// At least one invocation of the body threw an exception. + public static void For(int fromInclusive, int toExclusive, Action body) + { +#if SILVERLIGHT + Parallel.For(fromInclusive, toExclusive, body); +#else + if (Control.DisableParallelization || Control.NumberOfParallelWorkerThreads < 2) + { + for (var index = fromInclusive; index < toExclusive; index++) + { + body(index); + } + } + else + { + Parallel.ForEach( + Partitioner.Create(fromInclusive, toExclusive), + new ParallelOptions { MaxDegreeOfParallelism = Control.NumberOfParallelWorkerThreads }, + (range, loopState) => + { + for (var i = range.Item1; i < range.Item2; i++) + { + body(i); + } + }); + } +#endif + } + + /// + /// Aggregates a function over a loop. + /// + /// Starting index of the loop. + /// Ending index of the loop + /// The function to aggregate. + /// The sum of the function over the loop. + public static double Aggregate(int fromInclusive, int toExclusive, Func body) + { + var sync = new object(); + var sum = 0.0; + +#if SILVERLIGHT + Parallel.For( + fromInclusive, + toExclusive, + () => 0.0, + (i, localData) => localData += body(i), + localResult => + { + lock (sync) + { + sum += localResult; + } + }); +#else + + if (Control.DisableParallelization || Control.NumberOfParallelWorkerThreads < 2) + { + for (var index = fromInclusive; index < toExclusive; index++) + { + sum += body(index); + } + } + else + { + Parallel.ForEach( + Partitioner.Create(fromInclusive, toExclusive), + new ParallelOptions { MaxDegreeOfParallelism = Control.NumberOfParallelWorkerThreads }, + () => 0.0, + (range, loopState, localData) => + { + for (var i = range.Item1; i < range.Item2; i++) + { + localData += body(i); + } + + return localData; + }, + localResult => + { + lock (sync) + { + sum += localResult; + } + }); + } +#endif + return sum; + } + + /// + /// Executes each of the provided actions inside a discrete, asynchronous task. + /// + /// An array of actions to execute. + /// The actions array contains a null element. + /// An action threw an exception. + public static void Invoke(params Action[] actions) + { + Parallel.Invoke(actions); + } + } +} \ No newline at end of file diff --git a/src/Silverlight/Properties/AssemblyInfo.cs b/src/Silverlight/Properties/AssemblyInfo.cs index d9214ba6..e01c184a 100644 --- a/src/Silverlight/Properties/AssemblyInfo.cs +++ b/src/Silverlight/Properties/AssemblyInfo.cs @@ -44,4 +44,4 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] [assembly: Guid("7b66646f-f0ee-425d-9065-910d1937a2df")] [assembly: NeutralResourcesLanguage("en")] -[assembly: InternalsVisibleTo("MathNet.Numerics.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100ed2314a577643d859571b8b9307c6ff2670525c4598fbb307e57ea65ebf5d4417284cb3da9181636480b623f4db8cc3c1947244ba069df0df86e2431621f51a488f9929519a1c5d0ae595f6e2d0e4094685f0c1229ff658360acbb9f63f1a0258e984dda00dc7ad4fd16dbb550ec1ef8a11df138402b7c1998ee224e652c839b")] +//[assembly: InternalsVisibleTo("MathNet.Numerics.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100ed2314a577643d859571b8b9307c6ff2670525c4598fbb307e57ea65ebf5d4417284cb3da9181636480b623f4db8cc3c1947244ba069df0df86e2431621f51a488f9929519a1c5d0ae595f6e2d0e4094685f0c1229ff658360acbb9f63f1a0258e984dda00dc7ad4fd16dbb550ec1ef8a11df138402b7c1998ee224e652c839b")] diff --git a/src/Silverlight/Silverlight.csproj b/src/Silverlight/Silverlight.csproj index e5b3abf5..5c86bdbd 100644 --- a/src/Silverlight/Silverlight.csproj +++ b/src/Silverlight/Silverlight.csproj @@ -1,47 +1,28 @@  - - v3.5 - Debug AnyCPU - 9.0.30729 + 8.0.50727 2.0 - {0CCA2BA4-9DF2-4E9B-8A77-0A1F61A96A77} + {793E332F-E2B1-4D1D-9B2E-27E90B99BF93} {A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} Library Properties MathNet.Numerics MathNet.Numerics.Silverlight + Silverlight v4.0 + $(TargetFrameworkVersion) false true true - true - ..\MathNet.Numerics.snk - Silverlight - $(TargetFrameworkVersion) - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - + + + + v3.5 true @@ -53,7 +34,6 @@ true prompt 4 - AllRules.ruleset pdbonly @@ -64,12 +44,11 @@ true prompt 4 - AllRules.ruleset + - @@ -78,13 +57,13 @@ - Algorithms\ILinearAlgebraProvider.cs + Algorithms\LinearAlgebra\ILinearAlgebraProvider.cs - Algorithms\ILinearAlgebraProviderOfT.cs + Algorithms\LinearAlgebra\ILinearAlgebraProviderOfT.cs - Algorithms\ManagedLinearAlgebraProvider.cs + Algorithms\LinearAlgebra\ManagedLinearAlgebraProvider.cs Combinatorics.cs @@ -230,21 +209,6 @@ IPrecisionSupport.cs - - LinearAlgebra\Double\DenseMatrix.cs - - - LinearAlgebra\Double\DenseVector.cs - - - LinearAlgebra\Double\Matrix.Arithmetic.cs - - - LinearAlgebra\Double\Matrix.cs - - - LinearAlgebra\Double\Vector.cs - NumberTheory\IntegerTheory.cs @@ -255,7 +219,7 @@ Precision.cs - Properties\Resources.Designer.cs + Resources.Designer.cs Random\AbstractRandomNumberGenerator.cs @@ -338,49 +302,35 @@ Statistics\Statistics.cs + + Threading\CommonParallel.cs + Trigonometry.cs - - Version.cs - + + + + + - Properties\Resources.resx + Resources.resx - - MathNet.Numerics.snk + + Version.tt + TextTemplatingFileGenerator + Version1.cs - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - + - @@ -388,4 +338,11 @@ + \ No newline at end of file diff --git a/src/Silverlight/Threading/AggregateException.cs b/src/Silverlight/Threading/AggregateException.cs new file mode 100644 index 00000000..b1d6d042 --- /dev/null +++ b/src/Silverlight/Threading/AggregateException.cs @@ -0,0 +1,65 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// Copyright (c) 2009 Math.NET +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.Threading +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + + /// + /// Represents multiple errors that occur during application execution. + /// + public class AggregateException : Exception + { + /// + /// List of the aggregated exceptions. + /// + private readonly IList _exceptions = new List(); + + /// + /// Initializes a new instance of the AggregateException class with a specified error message and references to the inner exceptions that are the cause of this exception. + /// + /// The exceptions that are the cause of the current exception. + public AggregateException(IEnumerable exceptions) + { + foreach (var exception in exceptions) + { + this._exceptions.Add(exception); + } + } + + /// + /// Gets a read-only collection of the Exception instances that caused the current exception. + /// + /// A read-only collection of the Exception instances that caused the current exception + public ReadOnlyCollection InnerExceptions + { + get + { + return new ReadOnlyCollection(this._exceptions); + } + } + } +} \ No newline at end of file diff --git a/src/Silverlight/Threading/Parallel.cs b/src/Silverlight/Threading/Parallel.cs new file mode 100644 index 00000000..9c266a29 --- /dev/null +++ b/src/Silverlight/Threading/Parallel.cs @@ -0,0 +1,485 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.Threading +{ + using System; + using System.Collections.Generic; + using Properties; + + /// + /// Provides support for parallel loops. + /// + internal static class Parallel + { + /// + /// The amount to scale the foreach buffer after each iteration. + /// + private const int ScalingFactor = 2; + + /// + /// The maximum size of the foreach buffer. + /// + private const int MaxBlockSize = 65536; + + /// + /// The initial size of the for each buffer. + /// + private const int IntialBlockSize = 1024; + + /// + /// Executes a for loop in which iterations may run in parallel. + /// + /// The start index, inclusive. + /// The end index, exclusive. + /// The body to be invoked for each iteration. + /// The argument is null. + /// At least one invocation of the body threw an exception. + public static void For(int fromInclusive, int toExclusive, Action body) + { + if (body == null) + { + throw new ArgumentNullException("body"); + } + + // fast forward execution if it's only one or none items + var count = toExclusive - fromInclusive; + if (count <= 1) + { + if (count == 1) + { + body(fromInclusive); + } + + return; + } + + // fast forward execution in case parallelization is disabled + if (Control.DisableParallelization + || ThreadQueue.ThreadCount <= 1 + || ThreadQueue.IsInWorkerThread) + { + for (int i = fromInclusive; i < toExclusive; i++) + { + body(i); + } + + return; + } + + var actions = new Action[ThreadQueue.ThreadCount]; + var size = count / actions.Length; + + // partition the jobs into separate sets for each but the last worked thread + for (var i = 0; i < actions.Length - 1; i++) + { + var start = fromInclusive + (i * size); + var stop = fromInclusive + ((i + 1) * size); + + actions[i] = + () => + { + for (int j = start; j < stop; j++) + { + body(j); + } + }; + } + + // add another set for last worker thread + actions[actions.Length - 1] = + () => + { + for (int i = fromInclusive + ((actions.Length - 1) * size); i < toExclusive; i++) + { + body(i); + } + }; + + Invoke(actions); + } + + /// + /// Executes a for loop in which iterations may run in parallel. + /// + /// The type of the thread-local data. + /// The start index, inclusive. + /// The end index, exclusive. + /// The function delegate that returns the initial state of the local data for each thread. + /// The delegate that is invoked once per iteration. + /// The delegate that performs a final action on the local state of each thread. + public static void For(int fromInclusive, int toExclusive, Func localInit, Func body, Action localFinally) + { + var count = toExclusive - fromInclusive; + var tasks = new Task[ThreadQueue.ThreadCount]; + var size = count / tasks.Length; + + // fast forward execution if it's only one or none items + if (count <= 1) + { + if (count == 1) + { + localFinally(body(fromInclusive, localInit())); + } + + return; + } + + // fast forward execution in case parallelization is disabled + if (Control.DisableParallelization + || ThreadQueue.ThreadCount <= 1 + || ThreadQueue.IsInWorkerThread) + { + var localresult = localInit(); + for (var i = fromInclusive; i < toExclusive; i++) + { + localresult = body(i, localresult); + } + + localFinally(localresult); + return; + } + + // partition the jobs into separate sets for each but the last worked thread + for (var i = 0; i < tasks.Length - 1; i++) + { + var start = fromInclusive + (i * size); + var stop = fromInclusive + ((i + 1) * size); + tasks[i] = new Task( + localData => + { + var localresult = (T)localData; + for (var j = start; j < stop; j++) + { + localresult = body(j, localresult); + } + + return localresult; + }, + localInit()); + ThreadQueue.Enqueue(tasks[i]); + } + + // add another set for last worker thread + tasks[tasks.Length - 1] = new Task( + localData => + { + var localresult = (T)localData; + for (var i = fromInclusive + ((tasks.Length - 1) * size); i < toExclusive; i++) + { + localresult = body(i, localresult); + } + + return localresult; + }, + localInit()); + + ThreadQueue.Enqueue(tasks[tasks.Length - 1]); + if (tasks.Length <= 0) + { + return; + } + + WaitForTasksToComplete(tasks); + + foreach (var t in tasks) + { + localFinally(t.Result); + } + + CollectExceptions(tasks); + } + + /// + /// Executes a for each operation on an IEnumerable{T} in which iterations may run in parallel. + /// + /// The type of the data in the source. + /// An enumerable data source. + /// The delegate that is invoked once per iteration. + public static void ForEach(IEnumerable source, Action body) + { + if (body == null) + { + throw new ArgumentNullException("body"); + } + + // fast forward execution in case parallelization is disabled + if (Control.DisableParallelization + || ThreadQueue.ThreadCount <= 1 + || ThreadQueue.IsInWorkerThread) + { + foreach (var item in source) + { + body(item); + } + + return; + } + + // source is a IList, call For instead. + if (source is IList) + { + var list = (IList)source; + For(0, list.Count, i => body(list[i])); + return; + } + + var maxBlockSize = IntialBlockSize; + var tasks = new List(); + + var enumerator = source.GetEnumerator(); + while (enumerator.MoveNext()) + { + var pos = 0; + var list = new T[maxBlockSize]; + list[pos++] = enumerator.Current; + + var count = 1; + while (count < maxBlockSize && enumerator.MoveNext()) + { + list[pos++] = enumerator.Current; + count++; + } + + var task = new Task( + () => + { + for (var i = 0; i < pos; i++) + { + body(list[i]); + } + }); + + ThreadQueue.Enqueue(task); + tasks.Add(task); + maxBlockSize = Math.Min(MaxBlockSize, maxBlockSize * ScalingFactor); + } + + if (tasks.Count > 0) + { + WaitForTasksToComplete(tasks.ToArray()); + CollectExceptions(tasks); + } + } + + /// + /// Executes a for each operation on an IEnumerable{TSource in which iterations may run in parallel. + /// + /// The type of the data in the source. + /// The type of the thread-local data. + /// An enumerable data source. + /// The function delegate that returns the initial state of the local data for each thread. + /// The delegate that is invoked once per iteration. + /// The delegate that performs a final action on the local state of each thread. + public static void ForEach(IEnumerable source, Func localInit, Func body, Action localFinally) + { + if (body == null) + { + throw new ArgumentNullException("body"); + } + + // fast forward execution in case parallelization is disabled + if (Control.DisableParallelization + || ThreadQueue.ThreadCount <= 1 + || ThreadQueue.IsInWorkerThread) + { + var localResult = localInit(); + foreach (var item in source) + { + localResult = body(item, localResult); + } + + localFinally(localResult); + return; + } + + // source is a IList, call For instead. + if (source is IList) + { + var list = (IList)source; + For(0, list.Count, localInit, (i, local) => body(list[i], local), localFinally); + return; + } + + var maxBlockSize = IntialBlockSize; + var tasks = new List>(); + + var enumerator = source.GetEnumerator(); + while (enumerator.MoveNext()) + { + var pos = 0; + var list = new TSource[maxBlockSize]; + list[pos++] = enumerator.Current; + + var count = 1; + while (count < maxBlockSize && enumerator.MoveNext()) + { + list[pos++] = enumerator.Current; + count++; + } + + var task = new Task( + localData => + { + var localresult = localData; + for (var i = 0; i < pos; i++) + { + localresult = body(list[i], (TLocal)localresult); + } + + return (TLocal)localresult; + }, + localInit()); + + ThreadQueue.Enqueue(task); + tasks.Add(task); + maxBlockSize = Math.Min(MaxBlockSize, maxBlockSize * ScalingFactor); + } + + if (tasks.Count <= 0) + { + return; + } + + var taskArray = tasks.ToArray(); + WaitForTasksToComplete(taskArray); + + for (var i = 0; i < taskArray.Length; i++) + { + localFinally(tasks[i].Result); + } + + CollectExceptions(taskArray); + } + + /// + /// Executes each of the provided actions inside a discrete, asynchronous task. + /// + /// An array of actions to execute. + /// The argument is null. + /// The actions array contains a null element. + /// An action threw an exception. + public static void Run(params Action[] actions) + { + if (actions == null) + { + throw new ArgumentNullException("actions"); + } + + // fast forward execution if it's only one or none items + if (actions.Length <= 1) + { + if (actions.Length == 1) + { + actions[0](); + } + + return; + } + + // fast forward execution in case parallelization is disabled + if (Control.DisableParallelization + || ThreadQueue.ThreadCount <= 1 + || ThreadQueue.IsInWorkerThread) + { + for (var i = 0; i < actions.Length; i++) + { + actions[i](); + } + + return; + } + + Invoke(actions); + } + + /// + /// Executes each of the provided actions inside a discrete, asynchronous task. + /// + /// An array of actions to execute. + /// The actions array contains a null element. + /// An action threw an exception. + internal static void Invoke(params Action[] actions) + { + // create a job for each action + var tasks = new Task[actions.Length]; + for (var i = 0; i < tasks.Length; i++) + { + Action action = actions[i]; + if (action == null) + { + throw new ArgumentException(String.Format(Resources.ArgumentItemNull, "actions"), "actions"); + } + + tasks[i] = new Task(action); + } + + // run the jobs + ThreadQueue.Enqueue(tasks); + + WaitForTasksToComplete(tasks); + + CollectExceptions(tasks); + } + + /// + /// Waits for tasks to complete. + /// + /// The tasks. + private static void WaitForTasksToComplete(Task[] tasks) + { + foreach (var task in tasks) + { + task.Wait(); + } + } + + /// + /// Collects the exceptions and dispose tasks. + /// + /// The tasks. + private static void CollectExceptions(IEnumerable tasks) + { + // collect all thrown exceptions and dispose the jobs + var exceptions = new List(); + foreach (var task in tasks) + { + if (task.IsFaulted) + { + exceptions.Add(task.Exception); + } + } + + // throw the aggregated exceptions, if any + if (exceptions.Count > 0) + { + throw new AggregateException(exceptions); + } + } + } +} \ No newline at end of file diff --git a/src/Silverlight/Threading/Task.cs b/src/Silverlight/Threading/Task.cs new file mode 100644 index 00000000..2f330837 --- /dev/null +++ b/src/Silverlight/Threading/Task.cs @@ -0,0 +1,128 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.Threading +{ + using System; + using System.Threading; + + /// + /// Internal Parallel Task Handle. + /// + internal class Task + { + /// + /// Delegate to the task's action. + /// + private readonly System.Action _body; + + /// + /// Initializes a new instance of the Task class. + /// + /// Delegate to the task's action. + public Task(Action body) + { + if (body == null) + { + throw new ArgumentNullException("body"); + } + + _body = body; + } + + /// + /// Initializes a new instance of the class. + /// + protected Task() + { + } + + /// + /// Gets a value indicating whether the task completed due to an unhandled exception. + /// + /// + /// true if this task completed due to an unhandled exception; otherwise, false. + /// + public bool IsFaulted + { + get { return Exception != null; } + } + + /// + /// Gets a value indicating whether this task has completed. + /// + /// + /// true if this task has completed; otherwise, false. + /// + public bool IsCompleted + { + get; + private set; + } + + /// + /// Gets or sets the exception thrown by the task, if any. + /// + public Exception Exception { get; set; } + + /// + /// Run the task. + /// + public void Compute() + { + try + { + DoCompute(); + IsCompleted = true; + } + catch (Exception e) + { + Exception = e; + } + } + + /// + /// Runs the actual task. + /// + protected virtual void DoCompute() + { + _body(); + } + + /// + /// Waits for the task to complete execution. + /// + public void Wait() + { + while (!IsCompleted && !IsFaulted) + { + Thread.Sleep(0); + } + } + } +} \ No newline at end of file diff --git a/src/Silverlight/Threading/TaskOfT.cs b/src/Silverlight/Threading/TaskOfT.cs new file mode 100644 index 00000000..2cef39c2 --- /dev/null +++ b/src/Silverlight/Threading/TaskOfT.cs @@ -0,0 +1,79 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.Threading +{ + using System; + + /// + /// Internal Generic Parallel Task Handle. + /// + /// The type of the result. + internal class Task : Task + { + /// + /// Delegate to the task's action. + /// + private readonly Func _body; + + /// + /// Variable used to hold state information between iterations. + /// + private readonly object _state; + + /// + /// Gets the result of the task. + /// + /// The result of the task. + public TResult Result { get; private set; } + + /// + /// Initializes a new instance of the Task class. + /// + /// Delegate to the task's action. + /// An object representing data to be used by the action. + public Task(Func body, object state) + { + if (body == null) + { + throw new ArgumentNullException("body"); + } + + _state = state; + _body = body; + } + + /// + /// Runs the actual task. + /// + protected override void DoCompute() + { + Result = _body(_state); + } + } +} \ No newline at end of file diff --git a/src/Silverlight/Threading/ThreadQueue.cs b/src/Silverlight/Threading/ThreadQueue.cs new file mode 100644 index 00000000..8d58a946 --- /dev/null +++ b/src/Silverlight/Threading/ThreadQueue.cs @@ -0,0 +1,258 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://mathnet.opensourcedotnet.info +// +// Copyright (c) 2009 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.Threading +{ + using System; + using System.Collections.Generic; + using System.Threading; + + /// + /// Internal Parallel Thread Queue. + /// + internal static class ThreadQueue + { + /// + /// Sync Object for the thread queue state. + /// + private static readonly object _stateSync = new object(); + + /// + /// Sync Object for queue access (to be sure it's used by us only). + /// + private static readonly object _queueSync = new object(); + + /// + /// Queue holding the pending jobs. + /// + private static readonly Queue _queue = new Queue(); + + /// + /// Running flag, used to signal worker threads to stop cleanly. + /// + private static bool _running = true; + + /// + /// Worker threads + /// + private static Thread[] _threads; + + /// + /// Gets the number of worker threads. + /// + internal static int ThreadCount { get; private set; } + + /// + /// Indicating whether the current thread is a parallelized worker thread. + /// + [ThreadStatic] + private static bool _isInWorkerThread; + + /// + /// Initializes static members of the ThreadQueue class. + /// + static ThreadQueue() + { + Start(1); + } + + /// + /// Gets a value indicating whether the current thread is a parallelized worker thread. + /// + public static bool IsInWorkerThread + { + get { return _isInWorkerThread; } + } + + /// + /// Add a job to the queue. + /// + /// The job to run. + public static void Enqueue(Task task) + { + if (!_running) + { + Start(); + } + + lock (_queueSync) + { + _queue.Enqueue(task); + Monitor.Pulse(_queueSync); + } + } + + /// + /// Add a set of jobs to the queue. + /// + /// The jobs to run. + public static void Enqueue(IList tasks) + { + if (!_running) + { + Start(); + } + + lock (_queueSync) + { + foreach (var task in tasks) + { + _queue.Enqueue(task); + } + + Monitor.PulseAll(_queueSync); + } + } + + /// + /// Worker Thread Program + /// + private static void WorkerThreadStart() + { + _isInWorkerThread = true; + + while (_running) + { + // Get the job... + Task task = null; + + lock (_queueSync) + { + // Check whether we should shut down + if (!_running) + { + break; + } + + if (_queue.Count > 0) + { + task = _queue.Dequeue(); + } + else + { + Monitor.Wait(_queueSync); + } + } + + if (task == null) + { + continue; + } + + // ...and run it + task.Compute(); + } + + _isInWorkerThread = false; + } + + /// + /// Start or restart the queue with the specified number of worker threads. + /// + /// Number of worker threads. + public static void Start(int numberOfThreads) + { + lock (_stateSync) + { + // instead of throwing an out of range exception, simply normalize + numberOfThreads = Math.Max(1, Math.Min(1024, numberOfThreads)); + + if (_threads != null) + { + if (_threads.Length == numberOfThreads) + { + return; + } + + Shutdown(); + } + + ThreadCount = numberOfThreads; + Start(); + } + } + + /// + /// Start the thread queue, if it is not already running. + /// + public static void Start() + { + lock (_stateSync) + { + if (_threads != null) + { + return; + } + + _running = true; + + _threads = new Thread[ThreadCount]; + + for (var i = 0; i < _threads.Length; i++) + { + _threads[i] = new Thread(WorkerThreadStart) + { + IsBackground = true + }; + + _threads[i].Start(); + } + } + } + + /// + /// Stop the thread queue, if it is running. + /// + public static void Shutdown() + { + // try to stop the worker threads cleanly + lock (_stateSync) + { + if (_threads == null) + { + return; + } + + _running = false; + + lock (_queueSync) + { + Monitor.PulseAll(_queueSync); + } + + // wait until all threads have stopped + foreach (var thread in _threads) + { + thread.Join(); + } + + _threads = null; + } + } + } +} \ No newline at end of file