diff --git a/src/Npgsql/Internal/NpgsqlConnector.cs b/src/Npgsql/Internal/NpgsqlConnector.cs
index cedcfeac8b..cbfbaff6c4 100644
--- a/src/Npgsql/Internal/NpgsqlConnector.cs
+++ b/src/Npgsql/Internal/NpgsqlConnector.cs
@@ -190,7 +190,7 @@ internal string InferredUserName
/// cancellation is delivered. This reduces the chance that a cancellation meant for a previous
/// command will accidentally cancel a later one, see #615.
///
- object CancelLock { get; } = new();
+ Lock CancelLock { get; } = new();
///
/// A lock that's taken to make sure no other concurrent operation is running.
@@ -198,12 +198,12 @@ internal string InferredUserName
/// Anyone else should immediately check the state and exit
/// if the connector is closed.
///
- object SyncObj { get; } = new();
+ Lock SyncObj { get; } = new();
///
/// A lock that's used to wait for the Cleanup to complete while breaking the connection.
///
- object CleanupLock { get; } = new();
+ Lock CleanupLock { get; } = new();
readonly bool _isKeepAliveEnabled;
readonly Timer? _keepAliveTimer;
@@ -1918,7 +1918,7 @@ internal void PerformImmediateUserCancellation()
return;
// The connector is still alive, take the CancelLock before exiting SingleUseLock.
// If a break will happen after, it's going to wait for the cancellation to complete.
- Monitor.Enter(CancelLock);
+ CancelLock.Enter();
}
try
@@ -1939,7 +1939,7 @@ internal void PerformImmediateUserCancellation()
}
finally
{
- Monitor.Exit(CancelLock);
+ CancelLock.Exit();
}
}
@@ -1954,7 +1954,7 @@ void PerformDelayedUserCancellation()
return;
// The connector is still alive, take the CancelLock before exiting SingleUseLock.
// If a break will happen after, it's going to wait for the cancellation to complete.
- Monitor.Enter(CancelLock);
+ CancelLock.Enter();
}
try
@@ -1963,7 +1963,7 @@ void PerformDelayedUserCancellation()
}
finally
{
- Monitor.Exit(CancelLock);
+ CancelLock.Exit();
}
}
@@ -2265,14 +2265,14 @@ internal Exception Break(Exception reason, bool markHostAsOfflineOnConnecting =
{
Debug.Assert(!IsClosed);
- Monitor.Enter(SyncObj);
+ SyncObj.Enter();
var state = State;
if (state == ConnectorState.Broken)
{
// We're already broken.
// Exit SingleUseLock to unblock other threads (like cancellation).
- Monitor.Exit(SyncObj);
+ SyncObj.Exit();
// Wait for the break to complete before going forward.
lock (CleanupLock) { }
return reason;
@@ -2287,12 +2287,12 @@ internal Exception Break(Exception reason, bool markHostAsOfflineOnConnecting =
Interlocked.CompareExchange(ref _breakReason, reason, null);
State = ConnectorState.Broken;
// Take the CleanupLock while in SingleUseLock to make sure concurrent Break doesn't take it first.
- Monitor.Enter(CleanupLock);
+ CleanupLock.Enter();
}
finally
{
// Unblock other threads (like cancellation) to proceed and exit gracefully.
- Monitor.Exit(SyncObj);
+ SyncObj.Exit();
}
try
@@ -2343,7 +2343,7 @@ internal Exception Break(Exception reason, bool markHostAsOfflineOnConnecting =
}
finally
{
- Monitor.Exit(CleanupLock);
+ CleanupLock.Exit();
}
}
@@ -2801,7 +2801,7 @@ internal void EndUserAction()
void PerformKeepAlive(object? state)
{
Debug.Assert(_isKeepAliveEnabled);
- if (!Monitor.TryEnter(SyncObj))
+ if (!SyncObj.TryEnter())
return;
try
@@ -2833,7 +2833,7 @@ void PerformKeepAlive(object? state)
}
finally
{
- Monitor.Exit(SyncObj);
+ SyncObj.Exit();
}
}
diff --git a/src/Npgsql/TypeMapping/GlobalTypeMapper.cs b/src/Npgsql/TypeMapping/GlobalTypeMapper.cs
index b5b8d0f904..ceb5a16a14 100644
--- a/src/Npgsql/TypeMapping/GlobalTypeMapper.cs
+++ b/src/Npgsql/TypeMapping/GlobalTypeMapper.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
+using System.Threading;
using Npgsql.Internal;
using Npgsql.Internal.Postgres;
using Npgsql.Internal.ResolverFactories;
@@ -13,7 +14,7 @@ sealed class GlobalTypeMapper : INpgsqlTypeMapper
{
readonly UserTypeMapper _userTypeMapper = new();
readonly List _pluginResolverFactories = [];
- readonly object _sync = new();
+ readonly Lock _sync = new();
PgTypeInfoResolverFactory[] _typeMappingResolvers = [];
internal IEnumerable GetPluginResolverFactories()
diff --git a/src/Npgsql/Util/ResettableCancellationTokenSource.cs b/src/Npgsql/Util/ResettableCancellationTokenSource.cs
index 3218a7e629..b7e3fb39d0 100644
--- a/src/Npgsql/Util/ResettableCancellationTokenSource.cs
+++ b/src/Npgsql/Util/ResettableCancellationTokenSource.cs
@@ -25,7 +25,7 @@ sealed class ResettableCancellationTokenSource(TimeSpan timeout) : IDisposable
///
/// Used, so we wouldn't concurrently use the cts for the cancellation, while it's being disposed
///
- readonly object lockObject = new();
+ readonly Lock lockObject = new();
#if DEBUG
bool _isRunning;
diff --git a/test/Npgsql.Tests/Support/SingleThreadSynchronizationContext.cs b/test/Npgsql.Tests/Support/SingleThreadSynchronizationContext.cs
index a7fedad3d6..cdef857207 100644
--- a/test/Npgsql.Tests/Support/SingleThreadSynchronizationContext.cs
+++ b/test/Npgsql.Tests/Support/SingleThreadSynchronizationContext.cs
@@ -8,7 +8,7 @@ namespace Npgsql.Tests.Support;
sealed class SingleThreadSynchronizationContext : SynchronizationContext, IDisposable
{
readonly BlockingCollection _tasks = new();
- readonly object _lockObject = new();
+ readonly Lock _lockObject = new();
volatile Thread? _thread;
bool _doingWork;
diff --git a/test/Npgsql.Tests/Support/TestBase.cs b/test/Npgsql.Tests/Support/TestBase.cs
index bfbf562c75..ded0bada11 100644
--- a/test/Npgsql.Tests/Support/TestBase.cs
+++ b/test/Npgsql.Tests/Support/TestBase.cs
@@ -25,7 +25,7 @@ public abstract class TestBase
static readonly SemaphoreSlim DatabaseCreationLock = new(1);
- static readonly object dataSourceLockObject = new();
+ static readonly Lock dataSourceLockObject = new();
static ConcurrentDictionary DataSources = new(StringComparer.Ordinal);