dotnet / winforms

Windows Forms is a .NET UI framework for building Windows desktop applications.
MIT License
4.34k stars 963 forks source link

Refactor `lock` on `object` usage to `System.Threading.Lock` #11672

Closed elachlan closed 2 weeks ago

elachlan commented 1 month ago

In .NET9 there is the new System.Threading.Lock https://learn.microsoft.com/en-us/dotnet/api/system.threading.lock?view=net-9.0

It is recommended to use the EnterScope method with a language construct that automatically disposes the returned Lock.Scope such as the C# using keyword, or to use the C# lock keyword, as these ensure that the lock is exited in exceptional cases. These patterns might also have performance benefits over using Enter/TryEnter and Exit. The following code fragment illustrates various patterns for entering and exiting a lock.

Refactor the object used for the lock to Lock where appropriate. The new Lock class when used with lock() will not use system.threading.monitor, but instead will use system.threading.lock.

Benchmarks in this blog post suggest a 25% performance improvement in lock operations: https://steven-giesel.com/blogPost/4cf6d48a-ec9d-4c68-961c-31fd8d8c1340

There are some limitations, I think the team is best positioned to decide whats best here.

We won't make changes until C# takes the change to the lock keyword out of preview. https://github.com/dotnet/csharplang/issues/7104

elachlan commented 1 month ago

@kirsan31 I saw you commented on the runtime issue. What are your thoughts on this?

elachlan commented 1 month ago

@JeremyKuhne you might be able to shoot this down early.

elachlan commented 1 month ago

One thing I am wondering is if the heavy usage of lock (this) is on purpose?

JeremyKuhne commented 1 month ago

We can explore this when the feature leaves preview state.

elachlan commented 1 month ago

Runtime issue: https://github.com/dotnet/runtime/issues/34812 C# issue: https://github.com/dotnet/csharplang/issues/7104

kirsan31 commented 1 month ago

@kirsan31 I saw you commented on the runtime issue. What are your thoughts on this?

My thots on this:

  1. Need to wait until release.
  2. Need a full sets of benchmarks (with all usage types):
    • Acquire / release without waiting. I hope this must be faster then current object lock :)
    • Long time waiting. Must be at least not worse then current :)
    • Short time waiting. Here the main question because of SpinWait using. In some cases we can get better performance but in some case much worse (many short waiters will eat cpu ) :(

So if acquire/release without waiting will be faster (it must) then we can feel free to replace object locking in those cases where waiting is rare. In other cases some analysis will be needed I think...

elachlan commented 1 month ago

The code base locks a lot on this. Which usually isn't a good idea. I'd like this issue to review that as well.

elachlan commented 1 month ago

I've raised an roslyn-analyzer rule over at: https://github.com/dotnet/runtime/issues/106907

It would make changes like this easier.

elachlan commented 4 weeks ago

@lonitra do you know who we can ask about the new Lock type? I am wondering if we can use it based on this comment:

If we want to have a lock object type not integrated into Monitor, then there is quite a bit of work required to make sure it integrates with the diagnostics infrastructure and the threading model correctly. (Monitor is an interruptible lock as it uses a COM interruptible wait so that STA frameworks such as WinForms and WPF work correctly. Any other lock that is intended for general use will also need to follow those strictures.)

https://github.com/dotnet/runtime/issues/34812#issuecomment-612531493

JeremyKuhne commented 3 weeks ago

Going to do this in .NET 10. I'm comfortable enough with what I've read to commit to this.