-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SpinLock should be a class, not a struct #70266
Comments
Here is a proposal for that code to produce a warning: #33773.
That would be a breaking change, so I'm quite certain it's not going to happen. |
What would it break? |
If nothing else, it would be a binary breaking change. That is, it would break if you have a library that was compiled targeting a framework where it's a This is because the IL is different, e.g. calling ldarg.0
ldflda valuetype SpinLock C::Locker
call instance void SpinLock::Exit() But like this for a ldarg.0
ldfld class SpinLock C::Locker
callvirt instance void SpinLock::Exit() The difference between |
I don't think .net 6 version assemblies will call .net 7 ones by default though, will they? |
@mrpmorris They will, if they are run on .Net 7. Imagine I create a .Net 6 library that uses |
In which case, mark it as obsolete and create a class named My intention is to give the gist of it, not the technical solution. |
Tagging subscribers to this area: @mangod9 Issue DetailsWhen using a SpinLock, consuming code should be always referencing the same instance - as its purpose is to have shared state. At the moment, there are at least two easy ways of accidentally breaking the functionality of a SpinLock on account that it is a struct rather than a class.
This causes a copy of the SpinLock to be created every time it is used. So Making Another example is as follows:
This creates a copy of the SpinLock each time It seems the idea of a single-instance with shared state contradicts the idea of a struct that is copied to a new instance. Changing And, as far as I can see, there is no reason to ever want a SpinLock to be copied.
|
I’ll need to double check but making a value type a reference type is AFAIK a binary breaking change. In terms of functionality I don’t think we’d want a class-based
There are already other class-level synchronization primitives that can be used instead of |
What @terrajobst said. |
@stephentoub I read in a book that a SpinLock is better than lock() for short term locks because lock will put a thread to sleep if it can't get the lock, is that no longer true? |
|
I didn't know that, thanks! |
What was the book? |
The "short term" may be much shorter than you thought. Look at our comment on SpinLock type:
|
When using a SpinLock, consuming code should be always referencing the same instance - as its purpose is to have shared state.
At the moment, there are at least two easy ways of accidentally breaking the functionality of a SpinLock on account that it is a struct rather than a class.
private readonly SpinLock Locker = new()
This causes a copy of the SpinLock to be created every time it is used. So
Locker.Enter
works on a new instance, and effectively disables any lockingMaking
Locker
type membersreadonly
is a common practice, but the caveat here is "unless it's a SpinLock".Another example is as follows:
This creates a copy of the SpinLock each time
Locker.ExecuteLocked()
is called. To fix this we have to change the code tothis ref SpinLock locker
.It seems the idea of a single-instance with shared state contradicts the idea of a struct that is copied to a new instance.
Changing
SpinLock
to a class would allowreadonly
members (which is good practice) and avoid accidental copying on extension methods.And, as far as I can see, there is no reason to ever want a SpinLock to be copied.
The text was updated successfully, but these errors were encountered: