diff --git a/NEWS.md b/NEWS.md index e461f0c66f2d0..1ca745c5e270b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -100,6 +100,8 @@ Deprecated or removed --------------------- * `@spawn expr` from the `Distributed` standard library should be replaced with `@spawnat :any expr` ([#32600]). +* `Threads.Mutex` and `Threads.RecursiveSpinLock` have been removed; use `ReentrantLock` (preferred) or + `Threads.SpinLock` instead ([#32875]). External dependencies --------------------- diff --git a/base/deprecated.jl b/base/deprecated.jl index 130c86c1d65c8..1f185ff83df12 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -188,3 +188,12 @@ MPFR.BigFloat(x::Real, prec::Int) = BigFloat(x; precision=prec) MPFR.BigFloat(x::Real, prec::Int, rounding::RoundingMode) = BigFloat(x, rounding; precision=prec) # END 1.0 deprecations + +# BEGIN 1.3 deprecations + +@eval Threads begin + Base.@deprecate_binding RecursiveSpinLock ReentrantLock + Base.@deprecate_binding Mutex ReentrantLock +end + +# END 1.3 deprecations diff --git a/base/locks-mt.jl b/base/locks-mt.jl index bd2562a55aa91..2ef1f8e2b2a67 100644 --- a/base/locks-mt.jl +++ b/base/locks-mt.jl @@ -2,7 +2,7 @@ import .Base: unsafe_convert, lock, trylock, unlock, islocked, wait, notify, AbstractLock -export SpinLock, RecursiveSpinLock, Mutex +export SpinLock # Important Note: these low-level primitives defined here # are typically not for general usage @@ -24,9 +24,6 @@ Each [`lock`](@ref) must be matched with an [`unlock`](@ref). Test-and-test-and-set spin locks are quickest up to about 30ish contending threads. If you have more contention than that, perhaps a lock is the wrong way to synchronize. - -See also [`Mutex`](@ref) for a more efficient version on one core or if the -lock may be held for a considerable length of time. """ struct SpinLock <: AbstractLock handle::Atomic{Int} @@ -63,142 +60,3 @@ end function islocked(l::SpinLock) return l.handle[] != 0 end - -""" - RecursiveSpinLock() - -Creates a reentrant lock. -The same thread can acquire the lock as many times as required. -Each [`lock`](@ref) must be matched with an [`unlock`](@ref). - -See also [`SpinLock`](@ref) for a slightly faster version. - -See also [`Mutex`](@ref) for a more efficient version on one core or if the lock -may be held for a considerable length of time. -""" -struct RecursiveSpinLock <: AbstractLock - ownertid::Atomic{Int16} - handle::Atomic{Int} - RecursiveSpinLock() = new(Atomic{Int16}(0), Atomic{Int}(0)) -end - -function lock(l::RecursiveSpinLock) - if l.ownertid[] == threadid() - l.handle[] += 1 - return - end - while true - if l.handle[] == 0 - if atomic_cas!(l.handle, 0, 1) == 0 - l.ownertid[] = threadid() - return - end - end - ccall(:jl_cpu_pause, Cvoid, ()) - # Temporary solution before we have gc transition support in codegen. - ccall(:jl_gc_safepoint, Cvoid, ()) - end -end - -function trylock(l::RecursiveSpinLock) - if l.ownertid[] == threadid() - l.handle[] += 1 - return true - end - if l.handle[] == 0 - if atomic_cas!(l.handle, 0, 1) == 0 - l.ownertid[] = threadid() - return true - end - return false - end - return false -end - -function unlock(l::RecursiveSpinLock) - @assert(l.ownertid[] == threadid(), "unlock from wrong thread") - @assert(l.handle[] != 0, "unlock count must match lock count") - if l.handle[] == 1 - l.ownertid[] = 0 - l.handle[] = 0 - ccall(:jl_cpu_wake, Cvoid, ()) - else - l.handle[] -= 1 - end - return -end - -function islocked(l::RecursiveSpinLock) - return l.handle[] != 0 -end - -########################################## -# System Mutexes -########################################## - -# These are mutexes from libuv. -const UV_MUTEX_SIZE = ccall(:jl_sizeof_uv_mutex, Cint, ()) - -""" - Mutex() - -These are standard system mutexes for locking critical sections of logic. - -On Windows, this is a critical section object, -on pthreads, this is a `pthread_mutex_t`. - -See also [`SpinLock`](@ref) for a lighter-weight lock. -""" -mutable struct Mutex <: AbstractLock - ownertid::Int16 - handle::Ptr{Cvoid} - function Mutex() - m = new(zero(Int16), Libc.malloc(UV_MUTEX_SIZE)) - ccall(:uv_mutex_init, Cvoid, (Ptr{Cvoid},), m.handle) - finalizer(mutex_destroy, m) - return m - end -end - -unsafe_convert(::Type{Ptr{Cvoid}}, m::Mutex) = m.handle - -function mutex_destroy(x::Mutex) - h = x.handle - if h != C_NULL - x.handle = C_NULL - ccall(:uv_mutex_destroy, Cvoid, (Ptr{Cvoid},), h) - Libc.free(h) - nothing - end -end - -function lock(m::Mutex) - m.ownertid == threadid() && concurrency_violation() # deadlock - # Temporary solution before we have gc transition support in codegen. - # This could mess up gc state when we add codegen support. - gc_state = ccall(:jl_gc_safe_enter, Int8, ()) - ccall(:uv_mutex_lock, Cvoid, (Ptr{Cvoid},), m) - ccall(:jl_gc_safe_leave, Cvoid, (Int8,), gc_state) - m.ownertid = threadid() - return -end - -function trylock(m::Mutex) - m.ownertid == threadid() && concurrency_violation() # deadlock - r = ccall(:uv_mutex_trylock, Cint, (Ptr{Cvoid},), m) - if r == 0 - m.ownertid = threadid() - end - return r == 0 -end - -function unlock(m::Mutex) - m.ownertid == threadid() || concurrency_violation() - m.ownertid = 0 - ccall(:uv_mutex_unlock, Cvoid, (Ptr{Cvoid},), m) - return -end - -function islocked(m::Mutex) - return m.ownertid != 0 -end diff --git a/doc/src/base/multi-threading.md b/doc/src/base/multi-threading.md index 3508bbc0e3b53..d5dfc88f333f6 100644 --- a/doc/src/base/multi-threading.md +++ b/doc/src/base/multi-threading.md @@ -36,6 +36,5 @@ Base.@threadcall These building blocks are used to create the regular synchronization objects. ```@docs -Base.Threads.Mutex Base.Threads.SpinLock ``` diff --git a/src/sys.c b/src/sys.c index ab652d179f98f..52f2397347b9e 100644 --- a/src/sys.c +++ b/src/sys.c @@ -75,7 +75,6 @@ JL_DLLEXPORT uint32_t jl_getutf8(ios_t *s) return wc; } -JL_DLLEXPORT int jl_sizeof_uv_mutex(void) { return sizeof(uv_mutex_t); } JL_DLLEXPORT int jl_sizeof_off_t(void) { return sizeof(off_t); } #ifndef _OS_WINDOWS_ JL_DLLEXPORT int jl_sizeof_mode_t(void) { return sizeof(mode_t); } diff --git a/test/threads_exec.jl b/test/threads_exec.jl index 34c691d1ba0f5..700114c379826 100644 --- a/test/threads_exec.jl +++ b/test/threads_exec.jl @@ -2,7 +2,7 @@ using Test using Base.Threads -using Base.Threads: SpinLock, Mutex +using Base.Threads: SpinLock # threading constructs @@ -110,7 +110,6 @@ end @test threaded_add_locked(SpinLock, 0, 10000) == 10000 @test threaded_add_locked(ReentrantLock, 0, 10000) == 10000 -@test threaded_add_locked(Mutex, 0, 10000) == 10000 # Check if the recursive lock can be locked and unlocked correctly. let critical = ReentrantLock() @@ -151,7 +150,6 @@ end threaded_gc_locked(SpinLock) threaded_gc_locked(Threads.ReentrantLock) -threaded_gc_locked(Mutex) # Issue 14726 # Make sure that eval'ing in a different module doesn't mess up other threads