Browse Source

using common parallel class for both silverlight and .NET 4.0

pull/36/head
Marcus Cuda 16 years ago
parent
commit
fe5147fcda
  1. 1
      src/FSharpExamples/Apply.fs
  2. 1
      src/FSharpExamples/FSharpExamples.fsproj
  3. 10
      src/MathNet.Numerics.sln
  4. 635
      src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs
  5. 31
      src/Numerics/Control.cs
  6. 6
      src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.Bluestein.cs
  7. 33
      src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.Naive.cs
  8. 17
      src/Numerics/IntegralTransforms/Algorithms/DiscreteFourierTransform.RadixN.cs
  9. 27
      src/Numerics/IntegralTransforms/Algorithms/DiscreteHartleyTransform.Naive.cs
  10. 1
      src/Numerics/Numerics.csproj
  11. 147
      src/Numerics/Threading/CommonParallel.cs
  12. 2
      src/Silverlight/Properties/AssemblyInfo.cs
  13. 115
      src/Silverlight/Silverlight.csproj
  14. 65
      src/Silverlight/Threading/AggregateException.cs
  15. 485
      src/Silverlight/Threading/Parallel.cs
  16. 128
      src/Silverlight/Threading/Task.cs
  17. 79
      src/Silverlight/Threading/TaskOfT.cs
  18. 258
      src/Silverlight/Threading/ThreadQueue.cs

1
src/FSharpExamples/Apply.fs

@ -27,6 +27,7 @@
// </copyright>
module MathNet.Numerics.FSharp.Examples.Apply
open System.Numerics
open MathNet.Numerics
open MathNet.Numerics.LinearAlgebra.Double

1
src/FSharpExamples/FSharpExamples.fsproj

@ -37,6 +37,7 @@
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Numerics" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FSharp\FSharp.fsproj">

10
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

635
src/Numerics/Algorithms/LinearAlgebra/ManagedLinearAlgebraProvider.cs

File diff suppressed because it is too large

31
src/Numerics/Control.cs

@ -28,6 +28,7 @@
namespace MathNet.Numerics
{
using System;
using Algorithms.LinearAlgebra;
/// <summary>
@ -35,6 +36,13 @@ namespace MathNet.Numerics
/// </summary>
public static class Control
{
#if !SILVERLIGHT
/// <summary>
/// Initial number of threads to use;
/// </summary>
private static int _numberOfThreads = Environment.ProcessorCount;
#endif
/// <summary>
/// Initializes static members of the Control class.
/// </summary>
@ -75,5 +83,28 @@ namespace MathNet.Numerics
{
get; set;
}
/// <summary>
/// Gets or sets a value indicating how many parallel worker threads shall be used
/// when parallelization is applicable.
/// </summary>
/// <remarks>The Silverlight version of the library defaults to one thread.</remarks>
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
}
}
}

6
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;
/// <summary>
/// Complex Fast (FFT) Implementation of the Discrete Fourier Transform (DFT).
/// </summary>
@ -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)

33
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;
/// <summary>
/// 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;
}

17
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;
/// <summary>
/// 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));
}
}

27
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;
/// <summary>
/// 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;

1
src/Numerics/Numerics.csproj

@ -180,6 +180,7 @@
<Compile Include="Statistics\MCMC\RejectionSampler.cs" />
<Compile Include="Statistics\Statistics.cs" />
<Compile Include="Statistics\MCMC\UnivariateSliceSampler.cs" />
<Compile Include="Threading\CommonParallel.cs" />
<Compile Include="Trigonometry.cs" />
</ItemGroup>
<ItemGroup>

147
src/Numerics/Threading/CommonParallel.cs

@ -0,0 +1,147 @@
// <copyright file="CommonParallel.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.Threading
{
using System;
#if !SILVERLIGHT
using System.Collections.Concurrent;
using System.Threading.Tasks;
#endif
/// <summary>
/// Used to simplify parallel code, particularly between the .NET 4.0 and Silverlight Code.
/// </summary>
internal static class CommonParallel
{
/// <summary>
/// Executes a for loop in which iterations may run in parallel.
/// </summary>
/// <param name="fromInclusive">The start index, inclusive.</param>
/// <param name="toExclusive">The end index, exclusive.</param>
/// <param name="body">The body to be invoked for each iteration.</param>
/// <exception cref="ArgumentNullException">The <paramref name="body"/> argument is null.</exception>
/// <exception cref="AggregateException">At least one invocation of the body threw an exception.</exception>
public static void For(int fromInclusive, int toExclusive, Action<int> 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
}
/// <summary>
/// Aggregates a function over a loop.
/// </summary>
/// <param name="fromInclusive">Starting index of the loop.</param>
/// <param name="toExclusive">Ending index of the loop</param>
/// <param name="body">The function to aggregate.</param>
/// <returns>The sum of the function over the loop.</returns>
public static double Aggregate(int fromInclusive, int toExclusive, Func<int, double> 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;
}
/// <summary>
/// Executes each of the provided actions inside a discrete, asynchronous task.
/// </summary>
/// <param name="actions">An array of actions to execute.</param>
/// <exception cref="ArgumentException">The actions array contains a null element.</exception>
/// <exception cref="AggregateException">An action threw an exception.</exception>
public static void Invoke(params Action[] actions)
{
Parallel.Invoke(actions);
}
}
}

2
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")]

115
src/Silverlight/Silverlight.csproj

@ -1,47 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'">
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{0CCA2BA4-9DF2-4E9B-8A77-0A1F61A96A77}</ProjectGuid>
<ProjectGuid>{793E332F-E2B1-4D1D-9B2E-27E90B99BF93}</ProjectGuid>
<ProjectTypeGuids>{A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MathNet.Numerics</RootNamespace>
<AssemblyName>MathNet.Numerics.Silverlight</AssemblyName>
<TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
<SilverlightApplication>false</SilverlightApplication>
<ValidateXaml>true</ValidateXaml>
<ThrowErrorsInValidation>true</ThrowErrorsInValidation>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\MathNet.Numerics.snk</AssemblyOriginatorKeyFile>
<TargetFrameworkIdentifier>Silverlight</TargetFrameworkIdentifier>
<SilverlightVersion>$(TargetFrameworkVersion)</SilverlightVersion>
<FileUpgradeFlags>
</FileUpgradeFlags>
<OldToolsVersion>3.5</OldToolsVersion>
<UpgradeBackupLocation />
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<!-- This property group is only here to support building this project using the
MSBuild 3.5 toolset. In order to work correctly with this older toolset, it needs
to set the TargetFrameworkVersion to v3.5 -->
<PropertyGroup Condition="'$(MSBuildToolsVersion)' == '3.5'">
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -53,7 +34,6 @@
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -64,12 +44,11 @@
<NoConfig>true</NoConfig>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="System.Numerics, Version=2.0.5.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System.Windows" />
<Reference Include="mscorlib" />
<Reference Include="system" />
<Reference Include="System.Core" />
<Reference Include="System.Xml" />
@ -78,13 +57,13 @@
</ItemGroup>
<ItemGroup>
<Compile Include="..\Numerics\Algorithms\LinearAlgebra\ILinearAlgebraProvider.cs">
<Link>Algorithms\ILinearAlgebraProvider.cs</Link>
<Link>Algorithms\LinearAlgebra\ILinearAlgebraProvider.cs</Link>
</Compile>
<Compile Include="..\Numerics\Algorithms\LinearAlgebra\ILinearAlgebraProviderOfT.cs">
<Link>Algorithms\ILinearAlgebraProviderOfT.cs</Link>
<Link>Algorithms\LinearAlgebra\ILinearAlgebraProviderOfT.cs</Link>
</Compile>
<Compile Include="..\Numerics\Algorithms\LinearAlgebra\ManagedLinearAlgebraProvider.cs">
<Link>Algorithms\ManagedLinearAlgebraProvider.cs</Link>
<Link>Algorithms\LinearAlgebra\ManagedLinearAlgebraProvider.cs</Link>
</Compile>
<Compile Include="..\Numerics\Combinatorics.cs">
<Link>Combinatorics.cs</Link>
@ -230,21 +209,6 @@
<Compile Include="..\Numerics\IPrecisionSupport.cs">
<Link>IPrecisionSupport.cs</Link>
</Compile>
<Compile Include="..\Numerics\LinearAlgebra\Double\DenseMatrix.cs">
<Link>LinearAlgebra\Double\DenseMatrix.cs</Link>
</Compile>
<Compile Include="..\Numerics\LinearAlgebra\Double\DenseVector.cs">
<Link>LinearAlgebra\Double\DenseVector.cs</Link>
</Compile>
<Compile Include="..\Numerics\LinearAlgebra\Double\Matrix.Arithmetic.cs">
<Link>LinearAlgebra\Double\Matrix.Arithmetic.cs</Link>
</Compile>
<Compile Include="..\Numerics\LinearAlgebra\Double\Matrix.cs">
<Link>LinearAlgebra\Double\Matrix.cs</Link>
</Compile>
<Compile Include="..\Numerics\LinearAlgebra\Double\Vector.cs">
<Link>LinearAlgebra\Double\Vector.cs</Link>
</Compile>
<Compile Include="..\Numerics\NumberTheory\IntegerTheory.cs">
<Link>NumberTheory\IntegerTheory.cs</Link>
</Compile>
@ -255,7 +219,7 @@
<Link>Precision.cs</Link>
</Compile>
<Compile Include="..\Numerics\Properties\Resources.Designer.cs">
<Link>Properties\Resources.Designer.cs</Link>
<Link>Resources.Designer.cs</Link>
</Compile>
<Compile Include="..\Numerics\Random\AbstractRandomNumberGenerator.cs">
<Link>Random\AbstractRandomNumberGenerator.cs</Link>
@ -338,49 +302,35 @@
<Compile Include="..\Numerics\Statistics\Statistics.cs">
<Link>Statistics\Statistics.cs</Link>
</Compile>
<Compile Include="..\Numerics\Threading\CommonParallel.cs">
<Link>Threading\CommonParallel.cs</Link>
</Compile>
<Compile Include="..\Numerics\Trigonometry.cs">
<Link>Trigonometry.cs</Link>
</Compile>
<Compile Include="..\Numerics\Version.cs">
<Link>Version.cs</Link>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Threading\AggregateException.cs" />
<Compile Include="Threading\Parallel.cs" />
<Compile Include="Threading\Task.cs" />
<Compile Include="Threading\TaskOfT.cs" />
<Compile Include="Threading\ThreadQueue.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\Numerics\Properties\Resources.resx">
<Link>Properties\Resources.resx</Link>
<Link>Resources.resx</Link>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="..\MathNet.Numerics.snk">
<Link>MathNet.Numerics.snk</Link>
<None Include="..\Numerics\Version.tt">
<Link>Version.tt</Link>
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Version1.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
<Visible>False</Visible>
<ProductName>Windows Installer 3.1</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Silverlight\$(SilverlightVersion)\Microsoft.Silverlight.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{A1591282-1198-4647-A2B1-27E5FF5F6F3B}">
@ -388,4 +338,11 @@
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

65
src/Silverlight/Threading/AggregateException.cs

@ -0,0 +1,65 @@
// <copyright file="AggregateException.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.Threading
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
/// <summary>
/// Represents multiple errors that occur during application execution.
/// </summary>
public class AggregateException : Exception
{
/// <summary>
/// List of the aggregated exceptions.
/// </summary>
private readonly IList<Exception> _exceptions = new List<Exception>();
/// <summary>
/// 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.
/// </summary>
/// <param name="exceptions">The exceptions that are the cause of the current exception.</param>
public AggregateException(IEnumerable<Exception> exceptions)
{
foreach (var exception in exceptions)
{
this._exceptions.Add(exception);
}
}
/// <summary>
/// Gets a read-only collection of the Exception instances that caused the current exception.
/// </summary>
/// <value>A read-only collection of the Exception instances that caused the current exception</value>
public ReadOnlyCollection<Exception> InnerExceptions
{
get
{
return new ReadOnlyCollection<Exception>(this._exceptions);
}
}
}
}

485
src/Silverlight/Threading/Parallel.cs

@ -0,0 +1,485 @@
// <copyright file="Parallel.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.Threading
{
using System;
using System.Collections.Generic;
using Properties;
/// <summary>
/// Provides support for parallel loops.
/// </summary>
internal static class Parallel
{
/// <summary>
/// The amount to scale the foreach buffer after each iteration.
/// </summary>
private const int ScalingFactor = 2;
/// <summary>
/// The maximum size of the foreach buffer.
/// </summary>
private const int MaxBlockSize = 65536;
/// <summary>
/// The initial size of the for each buffer.
/// </summary>
private const int IntialBlockSize = 1024;
/// <summary>
/// Executes a for loop in which iterations may run in parallel.
/// </summary>
/// <param name="fromInclusive">The start index, inclusive.</param>
/// <param name="toExclusive">The end index, exclusive.</param>
/// <param name="body">The body to be invoked for each iteration.</param>
/// <exception cref="ArgumentNullException">The <paramref name="body"/> argument is null.</exception>
/// <exception cref="AggregateException">At least one invocation of the body threw an exception.</exception>
public static void For(int fromInclusive, int toExclusive, Action<int> 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);
}
/// <summary>
/// Executes a for loop in which iterations may run in parallel.
/// </summary>
/// <typeparam name="T">The type of the thread-local data.</typeparam>
/// <param name="fromInclusive">The start index, inclusive.</param>
/// <param name="toExclusive">The end index, exclusive.</param>
/// <param name="localInit">The function delegate that returns the initial state of the local data for each thread.</param>
/// <param name="body">The delegate that is invoked once per iteration.</param>
/// <param name="localFinally">The delegate that performs a final action on the local state of each thread.</param>
public static void For<T>(int fromInclusive, int toExclusive, Func<T> localInit, Func<int, T, T> body, Action<T> localFinally)
{
var count = toExclusive - fromInclusive;
var tasks = new Task<T>[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<T>(
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<T>(
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);
}
/// <summary>
/// Executes a for each operation on an IEnumerable{T} in which iterations may run in parallel.
/// </summary>
/// <typeparam name="T">The type of the data in the source.</typeparam>
/// <param name="source">An enumerable data source.</param>
/// <param name="body">The delegate that is invoked once per iteration.</param>
public static void ForEach<T>(IEnumerable<T> source, Action<T> 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<T>)
{
var list = (IList<T>)source;
For(0, list.Count, i => body(list[i]));
return;
}
var maxBlockSize = IntialBlockSize;
var tasks = new List<Task>();
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);
}
}
/// <summary>
/// Executes a for each operation on an IEnumerable{TSource in which iterations may run in parallel.
/// </summary>
/// <typeparam name="TSource">The type of the data in the source.</typeparam>
/// <typeparam name="TLocal">The type of the thread-local data.</typeparam>
/// <param name="source">An enumerable data source.</param>
/// <param name="localInit">The function delegate that returns the initial state of the local data for each thread.</param>
/// <param name="body">The delegate that is invoked once per iteration.</param>
/// <param name="localFinally">The delegate that performs a final action on the local state of each thread.</param>
public static void ForEach<TSource, TLocal>(IEnumerable<TSource> source, Func<TLocal> localInit, Func<TSource, TLocal, TLocal> body, Action<TLocal> 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<TSource>)
{
var list = (IList<TSource>)source;
For(0, list.Count, localInit, (i, local) => body(list[i], local), localFinally);
return;
}
var maxBlockSize = IntialBlockSize;
var tasks = new List<Task<TLocal>>();
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<TLocal>(
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);
}
/// <summary>
/// Executes each of the provided actions inside a discrete, asynchronous task.
/// </summary>
/// <param name="actions">An array of actions to execute.</param>
/// <exception cref="ArgumentNullException">The <paramref name="actions"/> argument is null.</exception>
/// <exception cref="ArgumentException">The actions array contains a null element.</exception>
/// <exception cref="AggregateException">An action threw an exception.</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);
}
/// <summary>
/// Executes each of the provided actions inside a discrete, asynchronous task.
/// </summary>
/// <param name="actions">An array of actions to execute.</param>
/// <exception cref="ArgumentException">The actions array contains a null element.</exception>
/// <exception cref="AggregateException">An action threw an exception.</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);
}
/// <summary>
/// Waits for tasks to complete.
/// </summary>
/// <param name="tasks">The tasks.</param>
private static void WaitForTasksToComplete(Task[] tasks)
{
foreach (var task in tasks)
{
task.Wait();
}
}
/// <summary>
/// Collects the exceptions and dispose tasks.
/// </summary>
/// <param name="tasks">The tasks.</param>
private static void CollectExceptions(IEnumerable<Task> tasks)
{
// collect all thrown exceptions and dispose the jobs
var exceptions = new List<Exception>();
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);
}
}
}
}

128
src/Silverlight/Threading/Task.cs

@ -0,0 +1,128 @@
// <copyright file="Task.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.Threading
{
using System;
using System.Threading;
/// <summary>
/// Internal Parallel Task Handle.
/// </summary>
internal class Task
{
/// <summary>
/// Delegate to the task's action.
/// </summary>
private readonly System.Action _body;
/// <summary>
/// Initializes a new instance of the Task class.
/// </summary>
/// <param name="body">Delegate to the task's action.</param>
public Task(Action body)
{
if (body == null)
{
throw new ArgumentNullException("body");
}
_body = body;
}
/// <summary>
/// Initializes a new instance of the <see cref="Task"/> class.
/// </summary>
protected Task()
{
}
/// <summary>
/// Gets a value indicating whether the task completed due to an unhandled exception.
/// </summary>
/// <value>
/// <c>true</c> if this task completed due to an unhandled exception; otherwise, <c>false</c>.
/// </value>
public bool IsFaulted
{
get { return Exception != null; }
}
/// <summary>
/// Gets a value indicating whether this task has completed.
/// </summary>
/// <value>
/// <c>true</c> if this task has completed; otherwise, <c>false</c>.
/// </value>
public bool IsCompleted
{
get;
private set;
}
/// <summary>
/// Gets or sets the exception thrown by the task, if any.
/// </summary>
public Exception Exception { get; set; }
/// <summary>
/// Run the task.
/// </summary>
public void Compute()
{
try
{
DoCompute();
IsCompleted = true;
}
catch (Exception e)
{
Exception = e;
}
}
/// <summary>
/// Runs the actual task.
/// </summary>
protected virtual void DoCompute()
{
_body();
}
/// <summary>
/// Waits for the task to complete execution.
/// </summary>
public void Wait()
{
while (!IsCompleted && !IsFaulted)
{
Thread.Sleep(0);
}
}
}
}

79
src/Silverlight/Threading/TaskOfT.cs

@ -0,0 +1,79 @@
// <copyright file="TaskOfT.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.Threading
{
using System;
/// <summary>
/// Internal Generic Parallel Task Handle.
/// </summary>
/// <typeparam name="TResult">The type of the result.</typeparam>
internal class Task<TResult> : Task
{
/// <summary>
/// Delegate to the task's action.
/// </summary>
private readonly Func<object, TResult> _body;
/// <summary>
/// Variable used to hold state information between iterations.
/// </summary>
private readonly object _state;
/// <summary>
/// Gets the result of the task.
/// </summary>
/// <value>The result of the task.</value>
public TResult Result { get; private set; }
/// <summary>
/// Initializes a new instance of the Task class.
/// </summary>
/// <param name="body">Delegate to the task's action.</param>
/// <param name="state">An object representing data to be used by the action.</param>
public Task(Func<object, TResult> body, object state)
{
if (body == null)
{
throw new ArgumentNullException("body");
}
_state = state;
_body = body;
}
/// <summary>
/// Runs the actual task.
/// </summary>
protected override void DoCompute()
{
Result = _body(_state);
}
}
}

258
src/Silverlight/Threading/ThreadQueue.cs

@ -0,0 +1,258 @@
// <copyright file="ThreadQueue.cs" company="Math.NET">
// 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.
// </copyright>
namespace MathNet.Numerics.Threading
{
using System;
using System.Collections.Generic;
using System.Threading;
/// <summary>
/// Internal Parallel Thread Queue.
/// </summary>
internal static class ThreadQueue
{
/// <summary>
/// Sync Object for the thread queue state.
/// </summary>
private static readonly object _stateSync = new object();
/// <summary>
/// Sync Object for queue access (to be sure it's used by us only).
/// </summary>
private static readonly object _queueSync = new object();
/// <summary>
/// Queue holding the pending jobs.
/// </summary>
private static readonly Queue<Task> _queue = new Queue<Task>();
/// <summary>
/// Running flag, used to signal worker threads to stop cleanly.
/// </summary>
private static bool _running = true;
/// <summary>
/// Worker threads
/// </summary>
private static Thread[] _threads;
/// <summary>
/// Gets the number of worker threads.
/// </summary>
internal static int ThreadCount { get; private set; }
/// <summary>
/// Indicating whether the current thread is a parallelized worker thread.
/// </summary>
[ThreadStatic]
private static bool _isInWorkerThread;
/// <summary>
/// Initializes static members of the ThreadQueue class.
/// </summary>
static ThreadQueue()
{
Start(1);
}
/// <summary>
/// Gets a value indicating whether the current thread is a parallelized worker thread.
/// </summary>
public static bool IsInWorkerThread
{
get { return _isInWorkerThread; }
}
/// <summary>
/// Add a job to the queue.
/// </summary>
/// <param name="task">The job to run.</param>
public static void Enqueue(Task task)
{
if (!_running)
{
Start();
}
lock (_queueSync)
{
_queue.Enqueue(task);
Monitor.Pulse(_queueSync);
}
}
/// <summary>
/// Add a set of jobs to the queue.
/// </summary>
/// <param name="tasks">The jobs to run.</param>
public static void Enqueue(IList<Task> tasks)
{
if (!_running)
{
Start();
}
lock (_queueSync)
{
foreach (var task in tasks)
{
_queue.Enqueue(task);
}
Monitor.PulseAll(_queueSync);
}
}
/// <summary>
/// Worker Thread Program
/// </summary>
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;
}
/// <summary>
/// Start or restart the queue with the specified number of worker threads.
/// </summary>
/// <param name="numberOfThreads">Number of worker threads.</param>
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();
}
}
/// <summary>
/// Start the thread queue, if it is not already running.
/// </summary>
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();
}
}
}
/// <summary>
/// Stop the thread queue, if it is running.
/// </summary>
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;
}
}
}
}
Loading…
Cancel
Save