Skip to content

Is the double-checked locking pattern in BuildManager correct? #10260

Closed
@omajid

Description

@omajid

if (!_disposed)
{
if (disposing)
{
lock (_syncLock)
{
// We should always have finished cleaning up before calling Dispose.
RequireState(BuildManagerState.Idle, "ShouldNotDisposeWhenBuildManagerActive");
_componentFactories?.ShutdownComponents();
if (_workQueue != null)
{
_workQueue.Complete();
_workQueue = null;
}
if (_executionCancellationTokenSource != null)
{
_executionCancellationTokenSource.Cancel();
_executionCancellationTokenSource = null;
}
if (_noActiveSubmissionsEvent != null)
{
_noActiveSubmissionsEvent.Dispose();
_noActiveSubmissionsEvent = null;
}
if (_noNodesActiveEvent != null)
{
_noNodesActiveEvent.Dispose();
_noNodesActiveEvent = null;
}
if (ReferenceEquals(this, s_singletonInstance))
{
s_singletonInstance = null;
}
_disposed = true;
}
}
}
}

This doesn't quite match the double-checked locking pattern described at:

https://github.com/dotnet/runtime/blob/main/docs/design/specs/Memory-model.md#examples-and-common-patterns

It seems it might be possible to see a stale value of _disposed and then enter the lock and do the cleanup operations again. Is this safe to do because the cleanup operations are idempotent?

Metadata

Metadata

Assignees

Labels

Priority:2Work that is important, but not critical for the releasehelp wantedIssues that the core team doesn't plan to work on, but would accept a PR for. Comment to claim.triaged

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions