Skip to content

Commit 73117ba

Browse files
Merge pull request #170 from SpiceSharp/thread-safety-fixes
Few thread-safety fixes
2 parents f43e3ef + adee3e5 commit 73117ba

6 files changed

Lines changed: 37 additions & 68 deletions

File tree

.github/workflows/test-windows.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ jobs:
5555
args:
5656
# Unique keys of your project and organization. You can find them in SonarCloud > Information (bottom-left menu)
5757
# mandatory
58-
-Dsonar.projectKey="SpiceSharp_SpiceSharpParser"
58+
-Dsonar.projectKey="SpiceSharp_SpiceSharpParserNew"
5959
-Dsonar.organization="spicesharp"
6060
# Comma-separated paths to directories containing main source files.
6161
#-Dsonar.sources= # optional, default is project base directory

src/SpiceSharpParser/Common/Mathematics/Probability/DefaultRandomNumberProviderFactory.cs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,17 @@ public IRandomNumberProvider GetRandom(int? randomSeed)
4848
_cacheLock.EnterWriteLock();
4949
try
5050
{
51-
var randomGenerator = new DefaultRandomNumberProvider(new Random(randomSeed.Value));
52-
_randomGenerators[randomSeed.Value] = randomGenerator;
53-
54-
return randomGenerator;
51+
// Double-check after entering write lock
52+
if (!_randomGenerators.ContainsKey(randomSeed.Value))
53+
{
54+
var randomGenerator = new DefaultRandomNumberProvider(new Random(randomSeed.Value));
55+
_randomGenerators[randomSeed.Value] = randomGenerator;
56+
return randomGenerator;
57+
}
58+
else
59+
{
60+
return _randomGenerators[randomSeed.Value];
61+
}
5562
}
5663
finally
5764
{

src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Updates/EntityUpdates.cs

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -103,19 +103,14 @@ public void Add(IEntity entity, string parameterName, string expression, bool be
103103
throw new ArgumentNullException(nameof(expression));
104104
}
105105

106-
if (!SimulationSpecificUpdates.ContainsKey(simulation))
107-
{
108-
SimulationSpecificUpdates[simulation] = new Dictionary<IEntity, EntityUpdate>();
109-
}
110-
111-
if (!SimulationSpecificUpdates[simulation].ContainsKey(entity))
112-
{
113-
SimulationSpecificUpdates[simulation][entity] = new EntityUpdate();
114-
}
106+
var simulationUpdates = SimulationSpecificUpdates.GetOrAdd(simulation, _ => new Dictionary<IEntity, EntityUpdate>());
107+
var entityUpdate = simulationUpdates.ContainsKey(entity)
108+
? simulationUpdates[entity]
109+
: (simulationUpdates[entity] = new EntityUpdate());
115110

116111
if (beforeTemperature)
117112
{
118-
SimulationSpecificUpdates[simulation][entity].ParameterUpdatesBeforeTemperature.Add(new EntityParameterExpressionValueUpdate()
113+
entityUpdate.ParameterUpdatesBeforeTemperature.Add(new EntityParameterExpressionValueUpdate()
119114
{
120115
Expression = new DynamicExpression(expression),
121116
ParameterName = parameterName,
@@ -140,14 +135,11 @@ public void Add(IEntity entity, string parameterName, string expression, bool be
140135
throw new ArgumentNullException(nameof(expression));
141136
}
142137

143-
if (!CommonUpdates.ContainsKey(entity))
144-
{
145-
CommonUpdates[entity] = new EntityUpdate();
146-
}
138+
var entityUpdate = CommonUpdates.GetOrAdd(entity, _ => new EntityUpdate());
147139

148140
if (beforeTemperature)
149141
{
150-
CommonUpdates[entity].ParameterUpdatesBeforeTemperature.Add(new EntityParameterExpressionValueUpdate()
142+
entityUpdate.ParameterUpdatesBeforeTemperature.Add(new EntityParameterExpressionValueUpdate()
151143
{
152144
Expression = new DynamicExpression(expression),
153145
ParameterName = parameterName,
@@ -167,14 +159,11 @@ public void Add(IEntity entity, string parameterName, double value, bool beforeT
167159
throw new ArgumentNullException(nameof(parameterName));
168160
}
169161

170-
if (!CommonUpdates.ContainsKey(entity))
171-
{
172-
CommonUpdates[entity] = new EntityUpdate();
173-
}
162+
var entityUpdate = CommonUpdates.GetOrAdd(entity, _ => new EntityUpdate());
174163

175164
if (beforeTemperature)
176165
{
177-
CommonUpdates[entity].ParameterUpdatesBeforeTemperature.Add(
166+
entityUpdate.ParameterUpdatesBeforeTemperature.Add(
178167
new EntityParameterDoubleValueUpdate() { ParameterName = parameterName, Value = value });
179168
}
180169
}
@@ -196,19 +185,14 @@ public void Add(IEntity entity, string parameterName, double value, bool beforeT
196185
throw new ArgumentNullException(nameof(parameterName));
197186
}
198187

199-
if (!SimulationSpecificUpdates.ContainsKey(simulation))
200-
{
201-
SimulationSpecificUpdates[simulation] = new Dictionary<IEntity, EntityUpdate>();
202-
}
203-
204-
if (!SimulationSpecificUpdates[simulation].ContainsKey(entity))
205-
{
206-
SimulationSpecificUpdates[simulation][entity] = new EntityUpdate();
207-
}
188+
var simulationUpdates = SimulationSpecificUpdates.GetOrAdd(simulation, _ => new Dictionary<IEntity, EntityUpdate>());
189+
var entityUpdate = simulationUpdates.ContainsKey(entity)
190+
? simulationUpdates[entity]
191+
: (simulationUpdates[entity] = new EntityUpdate());
208192

209193
if (beforeTemperature)
210194
{
211-
SimulationSpecificUpdates[simulation][entity].ParameterUpdatesBeforeTemperature.Add(new EntityParameterDoubleValueUpdate { ParameterName = parameterName, Value = value });
195+
entityUpdate.ParameterUpdatesBeforeTemperature.Add(new EntityParameterDoubleValueUpdate { ParameterName = parameterName, Value = value });
212196
}
213197
}
214198

src/SpiceSharpParser/ModelReaders/Netlist/Spice/Context/Updates/SimulationUpdates.cs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,8 @@ public void AddBeforeSetup(ISimulationWithEvents simulation, Action<ISimulationW
8383
throw new ArgumentNullException(nameof(simulation));
8484
}
8585

86-
if (!SimulationBeforeSetupActions.ContainsKey(simulation))
87-
{
88-
SimulationBeforeSetupActions[simulation] = new List<SimulationUpdateAction>() { new SimulationUpdateAction(action) };
89-
}
90-
else
91-
{
92-
SimulationBeforeSetupActions[simulation].Add(new SimulationUpdateAction(action));
93-
}
86+
var actions = SimulationBeforeSetupActions.GetOrAdd(simulation, _ => new List<SimulationUpdateAction>());
87+
actions.Add(new SimulationUpdateAction(action));
9488
}
9589

9690
public void AddBeforeTemperature(ISimulationWithEvents simulation, Action<ISimulationWithEvents, SimulationEvaluationContexts> action)
@@ -100,14 +94,8 @@ public void AddBeforeTemperature(ISimulationWithEvents simulation, Action<ISimul
10094
throw new ArgumentNullException(nameof(simulation));
10195
}
10296

103-
if (!SimulationBeforeTemperatureActions.ContainsKey(simulation))
104-
{
105-
SimulationBeforeTemperatureActions[simulation] = new List<SimulationUpdateAction>() { new SimulationUpdateAction(action) };
106-
}
107-
else
108-
{
109-
SimulationBeforeTemperatureActions[simulation].Add(new SimulationUpdateAction(action));
110-
}
97+
var actions = SimulationBeforeTemperatureActions.GetOrAdd(simulation, _ => new List<SimulationUpdateAction>());
98+
actions.Add(new SimulationUpdateAction(action));
11199
}
112100

113101
public void AddBeforeSetup(Action<ISimulationWithEvents, SimulationEvaluationContexts> action)

src/SpiceSharpParser/ModelReaders/Netlist/Spice/Readers/Controls/Simulations/Decorators/EnableStochasticModelsSimulationDecorator.cs

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using SpiceSharp.Entities;
2-
using SpiceSharp.Simulations;
32
using SpiceSharpParser.Common;
43
using SpiceSharpParser.ModelReaders.Netlist.Spice.Context;
54
using SpiceSharpParser.ModelReaders.Netlist.Spice.Context.Models;
@@ -14,7 +13,7 @@ namespace SpiceSharpParser.ModelReaders.Netlist.Spice.Readers.Controls.Simulatio
1413
public class EnableStochasticModelsSimulationDecorator
1514
{
1615
private readonly IReadingContext _context;
17-
private readonly ConcurrentDictionary<string, Dictionary<string, double>> _lotValues = new ();
16+
private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, double>> _lotValues = new ();
1817

1918
public EnableStochasticModelsSimulationDecorator(IReadingContext context)
2019
{
@@ -98,22 +97,13 @@ private void SetModelDevModelParameters(ISimulationWithEvents simulation, IEntit
9897

9998
private double GetValueForLotParameter(EvaluationContext evaluationContext, string baseModel, string parameterName, double currentValue, double percentValue, string distributionName, IEqualityComparer<string> comparer)
10099
{
101-
if (_lotValues.ContainsKey(baseModel) && _lotValues[baseModel].ContainsKey(parameterName))
102-
{
103-
return _lotValues[baseModel][parameterName];
104-
}
105-
106-
var random = evaluationContext.Randomizer.GetRandomProvider(distributionName);
107-
double newValue = currentValue + ((percentValue / 100.0) * currentValue * random.NextSignedDouble());
100+
var modelValues = _lotValues.GetOrAdd(baseModel, _ => new ConcurrentDictionary<string, double>(comparer));
108101

109-
if (!_lotValues.ContainsKey(baseModel))
102+
return modelValues.GetOrAdd(parameterName, _ =>
110103
{
111-
_lotValues[baseModel] = new Dictionary<string, double>(comparer);
112-
}
113-
114-
_lotValues[baseModel][parameterName] = newValue;
115-
116-
return newValue;
104+
var random = evaluationContext.Randomizer.GetRandomProvider(distributionName);
105+
return currentValue + ((percentValue / 100.0) * currentValue * random.NextSignedDouble());
106+
});
117107
}
118108
}
119109
}

src/SpiceSharpParser/SpiceSharpParser.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<StartupObject />
2323
<PackageLicenseExpression>MIT</PackageLicenseExpression>
2424
<LangVersion>latest</LangVersion>
25-
<Version>3.2.5</Version>
25+
<Version>3.2.6</Version>
2626
</PropertyGroup>
2727

2828
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard1.5|AnyCPU'">

0 commit comments

Comments
 (0)