No video

How Thread Safety is Changing in .NET 9

  Рет қаралды 36,576

Nick Chapsas

Nick Chapsas

Күн бұрын

Get our Singleton Course for free: dometrain.com/...
Check out our new OpenTelemetry course: dometrain.com/...
Become a Patreon and get special perks: / nickchapsas
Hello, everybody. I'm Nick, and in this video, I will introduce you to a new C# type coming in .NET 9, which is how you will be doing locking and thread safety from now on.
Workshops: bit.ly/nickwor...
Don't forget to comment, like and subscribe :)
Social Media:
Follow me on GitHub: github.com/Elf...
Follow me on Twitter: / nickchapsas
Connect on LinkedIn: / nick-chapsas
Keep coding merch: keepcoding.shop
#csharp #dotnet

Пікірлер: 155
@user-zz6fk8bc8u
@user-zz6fk8bc8u Ай бұрын
The padlock at 2:50 should really be non-static because static would even lock across different instances which is not needed here. Nick very likely knows that but IMHO he skipped the details saying "we don't want to allocate every time" but the behavior is completely different it's not just about allocating for each instance and allocating once.
@zpa89
@zpa89 Ай бұрын
This makes me wonder... It makes sense, but if you are going to do that, why not lock `this` instead? I think I could see issues if something else locks your class but it seems like it would generally work fine
@bodziotoja
@bodziotoja Ай бұрын
@@zpa89 Yep, you have pointed out the issue. You really do not want to lock on something someone else can lock on. Debugging this kind of problems could get really tricky.
@nocturne6320
@nocturne6320 Ай бұрын
EDIT: as @dammej pointed out, this will actually break thread safety, didn't think it through :p It could be easily solved like this: [ThreadStatic] private static object? _lock; //Use this private static object Lock => _lock ??= new(); This way you're still avoiding repeated allocations, but it still keeps it thread safe.
@zpa89
@zpa89 Ай бұрын
@@nocturne6320 repeated allocations of an empty object really aren't going to hurt you. You should avoid micro optimizations like that until you get to a point where you know you are having issues and you have run a profiler that shows you the actual allocation of that empty object is a noticeable bottleneck.
@martinprohn2433
@martinprohn2433 Ай бұрын
@@nocturne6320 That would not work! Consider this: Parallel creates multiple threads. All threads use Monitor.Enter to wait for other threads who are currently in the critical section. With [ThreadStatic] instead of every thread observing the same lock object, every thread would instead wait for their own lock object. This would obviously always be free. So we would end up again with with the race condition, that we started with.
@LasseVagstherKarlsen
@LasseVagstherKarlsen Ай бұрын
7:45 Slightly incorrect about TryEnter with a timeout, the lock will not be exited if you hold it too long, the timeout specifies how long TryEnter should wait to try to grab the lock, and then fail and return false if it is unable to do so in that time. There is no mechanism that will automatically release the lock, except for whatever you write into your own code.
@billy65bob
@billy65bob Ай бұрын
Could just be an implementation detail?
@andreydeev4342
@andreydeev4342 Ай бұрын
My comment might be a bit off topic, but for some operations, including the example from video sum of integers, there is a good choice to use lock-free instructions. See Interlocked class, which allows thread-safe adding of two integers: Interlocked.Add(ref _sum, number); There is also interesting topic - compare-and-swap (CAS) algorythm, in C# it can be achieved with Interlocked.CompareExchange. There are even some lock-free thread-safe data structures (like hashtables), based on this algorythm, and maybe Nick finds it interesting to create a video on this topic.
@code8986
@code8986 9 күн бұрын
+1 for lock-free techniques
@jamesreynolds3167
@jamesreynolds3167 Ай бұрын
I'd love to hear more about how SemaphoreSlim and locks work with performance comparisons. When you'd use one over the other etc. I've always preferred SemaphoreSlim, as it allows me to control how many threads can be active in a block and also still make use of async await.
@mynameisshadywhat
@mynameisshadywhat Ай бұрын
Had to double check when this video was posted 4:45 you say C# 9 instead of .NET 9 😂
@AL12rs
@AL12rs Ай бұрын
I'd love to hear more about best practices and libraries for Async locking
@modernkennnern
@modernkennnern Ай бұрын
There's some talk about `await lock` similar to `await foreach` to allow asynchronous locking
@hellowill
@hellowill 9 күн бұрын
locks belong to threads so async lock doesn't really make sense IMO. Should be a semaphore.
@configadd
@configadd Ай бұрын
Still don't understand what problem the new approach solves? Its syntax has not changed much, and it also does not support asynchronous calls. What difference does it make how much faster it is if you're going to use SemaphoreSlim instead anyway?
@Kitulous
@Kitulous Ай бұрын
not all methods are async, so locking with the Lock class may still be useful
@fusedqyou
@fusedqyou Ай бұрын
FYI, SemaphoreSlim is efficient and also uses locking in the background. The point is avoiding the need to lock a thread completely until it can continue, and for synchronous code you just use this lock.
@andersborum9267
@andersborum9267 Ай бұрын
A key difference here is that you're allocading a ref struct instead of an object (i.e. the reference used in the lock() statement); also, the Lock type facilitates a number of different implementations that the Monitor type doesn't. I haven't moved to .NET 9 yet, but am keen on checking out the new API. In any case, for most developers, using the traditional approach is just fine for the majority of cases, yet retaining the ability to refactor for more modern types later.
@duffscs
@duffscs Ай бұрын
Mutex and semaphore require an os. (Not supported by browser, as anoted in source code). Lock is available on every platform even wasm, so they are getting ahead for wasm2 and multithreading operation support
@georgepagotelis
@georgepagotelis Ай бұрын
Especially since if you enable true in the project file couldn't it just improve the code if it's the same?
@julianocs87
@julianocs87 Ай бұрын
I had to check the date of the video when you mentioned C# 9 instead of .NET 9.
@leowong9885
@leowong9885 Ай бұрын
Brings back memory of intro class to OS - mutex, p & v, monitor, critical session... Thanks for introducing the new lock mechanism.
@TheTim466
@TheTim466 Ай бұрын
critical section*
@anonymous49125
@anonymous49125 Ай бұрын
for me in the first example with lock, I usually lock on the instance of the object itself (in this case the running instance of Example), rather than doing readonly and static a new object. If you have a shared static object as the lock argument, then it locks it for all Example instances, whereas locking on yourself (this instance) just locks it for you.
@code8986
@code8986 9 күн бұрын
You’re right that in this case the lock object shouldn’t have been static, but there are cases where it does need to be. In all cases, I prefer to have a dedicated lock object, but it’s not absolutely necessary.
@anonymous49125
@anonymous49125 9 күн бұрын
​@@code8986 I think that's a good preference. That said, I can't think of an instance where coordination/locking needs to be done with an external/dedicated object. If you have any suggestions at the ready, I would really appreciate your insight, because honestly, I can't think of any.
@silentdebugger
@silentdebugger Ай бұрын
I was really hoping the new Lock class would just work with async by default, given how many code paths are async in modern C#. Guess I was wrong.
@Tesfamichael.G
@Tesfamichael.G Ай бұрын
Thanks for the update. I have a question though. Is the topic about .NET 9 or C#9. at 4:46, recorded audio: 'starting from c# 9 ... '. I guess you mean .NET 9
@the-niker
@the-niker Ай бұрын
I expected this to be syntactic sugar for SemaphoreSlim that integrates into lock() keyword if a specific Lock type is detected. Left sorely disappointed, the amount of code where I use a lock in non-async code vs async code is like 5%. And frankly in that case I use sync version of my SemaphoreSlim wrapper anyway just to be consistent. This smells like a feature that Microsoft made for themselves to speed up the internals.
@duffscs
@duffscs Ай бұрын
Mutex and semaphore require an os. (Not supported by browser, as anoted in source code). Lock is available on every platform even wasm, so they are getting ahead for wasm2 and multithreading operation support
@davidantolingonzalez4929
@davidantolingonzalez4929 Ай бұрын
​@@duffscsSemaphoreSlim works in Wasm
@GlebAOsokin
@GlebAOsokin Ай бұрын
I've read somewhere, that acquiring a SemaphoreSlim is ~10x slower than acquiring a simple lock...
@the-niker
@the-niker Ай бұрын
@@GlebAOsokin lock() makes sense in specific scenarios in projects that are not asynchronous in nature, in parallel processing of non-I/O-bound data and maybe in low-level networking. I write mostly web and desktop and I would always opt for fully async execution tree in such projects. To be fair I would even do a console app be fully async with some rare exceptions. I don't want synchronous lock() in my projects. Async semaphore being even 50x slower is nothing compared to multiple threads doing the spinlock dance and hogging CPU cores. For me seeing lock() is a code smell once there's even a remote possibility the execution path may need to touch any kind of I/O. Converting lock to semaphore later is not always trivial.
@GlebAOsokin
@GlebAOsokin Ай бұрын
@@the-niker Well, async lock is already a very rare thing, since you normally don't want to block on a long-running operation, to say nothing of an IO-bound one. I use locks all the time and almost never SemaphoreSlim for the same purpose (although I do have a RAII-like disposable wrapper for it just in case). So I kinda understand, why .NET team implemented it the way they did.
@vacantbill
@vacantbill Ай бұрын
Just to touch on some of the comments, it is important to understand that the same thread can re-enter in a lock however a semaphore will prevent this unless there is an available counter (please correct me ife knowledge is out of date on this). I believe this is one of the reasons await and lock don't play that well together.
@YukonianOrangutangInSpace
@YukonianOrangutangInSpace Ай бұрын
Very informative, thank you! Excited for this.
@shanehebert396
@shanehebert396 Ай бұрын
The static padlock will restrict access and serialize *every* Example object, even though they are otherwise independent. You can make that a class member and it will then serialize for each object instance. You don't even need to allocate anything as each object has its own already... lock(this) { } will serialize access to that object (it's still a giant lock for everything that the object can do). You can make it even more fine grained by having a member variable specifically for Sum and locking it and having different padlocks for different members (if you had them).
@WileeRunner42
@WileeRunner42 Ай бұрын
Cool. This allows for the potential to have like an AsyncLock object or other behaviors. I do tend to write lock-free code but occasionally need a lock and then async rears its head. Then I'm back to a good old staple of my custom lock-free spin lock type of thing.
@ArcaneEye
@ArcaneEye Ай бұрын
isn't that just a semaphore?
@georgepagotelis
@georgepagotelis Ай бұрын
Thoughts on syntatic sugar should be covered by "true"? I feel like I'm be hood winked. If Span is running .NET 6-8 optimizations under the hood and other optimizations to improve speed. A new setting say "true" could ENFORCE the compiler to change the object to padLock conversion for older style code with a sledge hammer approach.
@phizc
@phizc Ай бұрын
You could use an analyzer to create an error if lock is used with anything other than a Lock object.
@trexug6577
@trexug6577 Ай бұрын
I keep adding Nito.AsyncEx to my projects. It's a fine library, but I would love it if MS would make some more built-in functionality for async locks. I don't want to spend my threads waiting for locks, when they have better things to do.
@vbjay
@vbjay Ай бұрын
Just wanted to point out the fix of using interlocked to do the sum without locking. But the point was the locking.
@MayronDev
@MayronDev Ай бұрын
A bit confused onj the difference between Enter and EnterScope. When and why would I need to create a lock scope? Why not just lock using the object?
@nickchapsas
@nickchapsas Ай бұрын
The lock scope will be created for you on the boundaries of the lock if you lock a lock type
@chralexNET
@chralexNET Ай бұрын
I think EnterScope creates a disposable Scope-object, so that you can use the using-keyword to automatically call Exit at the end of the scope. There may be more to it though, so best to read the official documentation.
@zglmorph
@zglmorph Ай бұрын
There should have been a dedicated Lock type starting back in .NET 1.0! As it is, every single heap-allocated object has extra overhead to be able to store locking information *just in case* someone might want to lock on that object, even though 99.9+% of objects will never be used as locks. AFAIK, the only reason they allowed everything to be usable in a lock statement is that they wanted to copy the Java idiom of "lock (this)". But Microsoft later came out with guidance saying not to use "lock (this)" because you don't want to lock on anything public, because if it's public then someone else could use it in their own lock statement, which could lead to deadlocks or data corruption. If they had come up with that guidance before .NET 1.0 was released, we might have had a Lock type in the very beginning.
@_grigoryta
@_grigoryta Ай бұрын
1:09 Paralyzed loop? Didn't know programming concepts could have disabilities. What a diverse world we live in
@artemisDev
@artemisDev Ай бұрын
When there's a deadlock in your parallelized loop.
@foxgodess9
@foxgodess9 Ай бұрын
Very useful in case of third party API calls, for example if you want to get the weather data of 10 locations at a time, or 10 days weather at a time but your third party API only supports one parameter for one call, then parallelize them and get all the results. it's fun lol
@rmcgraw7943
@rmcgraw7943 16 күн бұрын
SpinWait is your friend.
@adambickford8720
@adambickford8720 11 күн бұрын
Until it isnt
@pedrofpsimoes
@pedrofpsimoes Ай бұрын
I was happy for a while, but then it is the same hassle when using it with async-await LoL 😂
@fusedqyou
@fusedqyou Ай бұрын
.NET has always been weird when it comes to thread safety. I'd say thread safety with these things still remains very weird, but at least they address these things with more reasonable solutions.
@shahzaibhassan2777
@shahzaibhassan2777 Ай бұрын
I saw Rust's multi threading much easier to make sense of
@victor1882
@victor1882 Ай бұрын
@@shahzaibhassan2777 until async comes into the picture
@keyser456
@keyser456 Ай бұрын
Mutex / locks have been adequate for most situations in my experience (been on since 1.0 beta, circa 2002). The ReaderWriterLock/Slim was a nice addition. What has been weird in your experience, specifically?
@Rick104547
@Rick104547 Ай бұрын
How is .NET weird with thread safety? If anything its pretty standard.
@exemory
@exemory Ай бұрын
In this case with incrementing variable it's better to use Interlocked.CompareExchange method. This way you aren't blocking any threads and perform incrementing as an atomic operation
@phizc
@phizc Ай бұрын
How would that demonstrate the new Lock class?
@jongeduard
@jongeduard Ай бұрын
I would appreciate it if Microsoft took a longer look at how Rust has solved the whole thing. It's a very different approach and possibly we will get that after they have introduced more next level code validation in general, but it would be a great development if they could take some ideas from it at least. Now there are still lots of ways to accidentally introduce race conditions in your code, there is nothing which actively helps you guarantee that you do things the right way.
@mamicatatibe
@mamicatatibe Ай бұрын
6:53 Maybe I'm missing something, but shouldn't the IL code have the .EnterScope() functionality within the try-finally block as well so it makes sure the .Dispose() is called for the scope i.e. what if .EnterScope() blows up? (I haven't looked at what it does exactly, mind you)
@phizc
@phizc Ай бұрын
The try-finally block is to guarantee that the Monitor is exited if the was entered. Entering a try block can't fail, so the Monitor.Enter call can/should be outside it. The using statement works the same way in that the variable initialization is outside the try-finally block. E.g. using (var f = File.Open(fn)) { var b = f.ReadByte(); } becomes var f = File.Open(fn); try { var b = f.ReadByte(); } finally { f.Dispose(); }
@mamicatatibe
@mamicatatibe Ай бұрын
@@phizc thanks, for some reason I always thought it makes more sense for this to also be within the try block
@louisfrancisco2171
@louisfrancisco2171 Ай бұрын
@@mamicatatibe If the variable initialization is inside the try block, then the Dispose method could be called on an uninitialized variable.
@code8986
@code8986 9 күн бұрын
@@louisfrancisco2171The variable *declaration* needs to be outside of the try block, but couldn’t (and shouldn’t) the assignment (i.e. initialization) be *inside* the try block?
@louisfrancisco2171
@louisfrancisco2171 9 күн бұрын
@@code8986 If there were an exception between the start of the try block and the initialization, then the variable would be uninitialized. In the example above, if the file doesn't exist, execution would go to the finally block and you'd get a NullReferenceException from the call of Dispose on an unitialized variable.
@tarsala1995
@tarsala1995 Ай бұрын
`await` in `lock` is disallowed due to possible change of thread that is executing the code. Doubtful that MS will change that.
@heischono4917
@heischono4917 23 күн бұрын
Why do I still have to manually create a variable in the code? A user-friendly implementation of "lock {...}" could create a variable of type Lock internally. What is the reason that I must declare the Lock variable?
@dimonasdf
@dimonasdf 22 күн бұрын
You can lock multiple access points to the same collection with the same lock object. Also, the object should already exist when the thread's code arrive at try enter, otherwise all threads would create their own objects, and nothing would be locked :)
@diligencehumility6971
@diligencehumility6971 Ай бұрын
Would have been nice with a performance comparison
@rikudouensof
@rikudouensof Ай бұрын
Have not used lock before
@code8986
@code8986 9 күн бұрын
You’ve been lucky :)
@mikol0158
@mikol0158 Ай бұрын
Why using lock when you have semaphore slim?
@protox4
@protox4 Ай бұрын
9:54 I wrote one!
@eugene5096
@eugene5096 Ай бұрын
Not sure if this make a lot of difference if i would use Monitor explicitly
@mikewright2858
@mikewright2858 Ай бұрын
How is this better than the ReaderWriterLock?
@dusrdev
@dusrdev Ай бұрын
Is it supposed to replace only the simple lock on object, or types like the readerwriterlockslim as well?
@protox4
@protox4 Ай бұрын
The former.
@lordmetzgermeister
@lordmetzgermeister Ай бұрын
FYI you talk about new locks in C# 9 but it should be .NET 9
@DaminGamerMC
@DaminGamerMC Ай бұрын
I dont really get why the sum isnt getting computed correctly. I have used parallel foreach to process large documents and never have gotten into an issue where they dont finish what they should. Could someone explain?
@vasiliychernov2123
@vasiliychernov2123 Ай бұрын
Adding an int is not an atomic operation. It first needs to read current value, then add an int and then write it back. Two threads can read the same value, add their ints and write it back, and so one write will be lost. So you need either to create a critical section with mutex (lock keyword) or use lock-free atomic operations, such as compare-and-swap which is a CPU instruction. Read current value and add an int, then use CAS which does this: if current value is equal to a passed value (we pass the one we read previously, i.e. it checks if the value has changed), write the new value. If CAS fails, we do everything again. Value equality check and writing the value happens atomically in this case.
@DaminGamerMC
@DaminGamerMC Ай бұрын
@@vasiliychernov2123 Thanks, put in that way makes a lot of sense.
@phizc
@phizc Ай бұрын
In short it's a race condition.
@Tony-dp1rl
@Tony-dp1rl Ай бұрын
I can't think of a rational reason to lock an await call.
@marvinalone
@marvinalone 22 күн бұрын
C#9 or .Net 9 ?
@code8986
@code8986 9 күн бұрын
You’re right, he should’ve said .NET 9.
@cjrada82
@cjrada82 Ай бұрын
Why didn't they decide to support async code? - That's a disappointment
@GustavoHennig
@GustavoHennig Ай бұрын
The result is always different in kzfaq.info/get/bejne/mJqjiMiTrbW4mWg.html because you are not waiting for the Parallel.For to complete. This does not affect your point, but concurrency is not the cause of the value always being different. A more complex scenario would be required to demonstrate that.
@davilinkicefire
@davilinkicefire Ай бұрын
You partially right, he in fact doesn't check that the parallel.for is completed, but even if he waited for the run to complete, it would still result in having a different number at the end AND THE RESULT WILL STILL BE INCORRECT. The result at the end should equal to 1225 parallel.For doesn't not add thread-safety (or concurrency safety), is only that the 50 execution of the same code, and in the example, SHARE THE SAME REFERENCE of the class Example. You, as the developer, should ensure that the code that Parallel.For will execute is thread-safe (concurrency safe), Thread-safe mean that the code doesn't use share memory reference OR that they are protected against concurrency issue by issuing appropriate code synchronization mechanism (lock, semaphore, interlock, ...). he only use the parallel.for to quickly demonstrate a thread-safe issue that could be resolve by using a lock to demonstrate the new Lock type EDIT: remove the wrong end result
@JW-lv1fm
@JW-lv1fm Ай бұрын
@@davilinkicefire Factorial is multiplicative, hes doing additive. 1225 is 0 through 49 added.
@rauberhotzenplotz7722
@rauberhotzenplotz7722 Ай бұрын
Parallel.For is blocking
@davilinkicefire
@davilinkicefire Ай бұрын
@@JW-lv1fm You right, my bad
@GustavoHennig
@GustavoHennig Ай бұрын
@@rauberhotzenplotz7722 🤦‍♂You're right, it's blocking, I missed that.
@cocoscacao6102
@cocoscacao6102 Ай бұрын
Genuine question... What's the point of locking? It's just sequential code with extra steps...
@nickchapsas
@nickchapsas Ай бұрын
It’s about thread safety. Some operations might be 90% thread safe by default but they might have this 10% aspect of them that needs to be thread safe. You still gain 90% of performance by parallelizing most of it while locking what isn’t safe
@andersborum9267
@andersborum9267 Ай бұрын
It's basically to protect shared resources from race conditions, i.e. when two or more threads are competing for a limited resource (such as a shared integer, in Nick's example, which trivially could have been implemented using Interlocked.Increment).
@cocoscacao6102
@cocoscacao6102 Ай бұрын
@@nickchapsas Yeah but... have you ever encountered a situation where such code should exist? The best "real world" example that I can come up with is awaiting some multiple callbacks that eventually modify shared resource... But even then, I'd consider putting that operation in some queue or message broker... I never, ever used locks...
@sealsharp
@sealsharp Ай бұрын
​Queues made for concurrency hide the lock away from you.
@diadetediotedio6918
@diadetediotedio6918 Ай бұрын
@@cocoscacao6102 If you are implementing the queue processing you would use it.
@Michael.SMarsh
@Michael.SMarsh Ай бұрын
Sounds like it'd be way simpler to just do FP and avoid mutating objects like the plague, and then learn and utilize whatever transactional and/or concurrency capabilities your persistence layer provides since that would then be the only place you'd have to coordinate state changes. edit: unless your doing something low-level/non "web-dev" in which case I'm completely outside of my wheelhouse
@mattfbk
@mattfbk Ай бұрын
ReaderWriterLockSlim
@clhoover4
@clhoover4 Ай бұрын
Don't use static, ever, all instances will have the same lock
@user-zz6fk8bc8u
@user-zz6fk8bc8u Ай бұрын
In this case it was definitely wrong, but "ever" isn't true either. There are quite a few situations where static lock objects are the only good solution.
@clhoover4
@clhoover4 Ай бұрын
@@user-zz6fk8bc8u The challenge from my experience is static variables creates a tight coupling, impacting testing, refactoring, evolution of the system, thread safety, etc...
@ilyahryapko
@ilyahryapko Ай бұрын
@@user-zz6fk8bc8u can you elaborate please?
@RiversJ
@RiversJ 13 күн бұрын
And if it's a shared system resource, instance level locks are worse than useless. The only Hard rule for anything with programming is quite simple = Use the right tool for the job You do not want to be a cargo cultist going with the first paradigm you learned for every problem.
@jjxtra
@jjxtra 5 күн бұрын
Interlocked.*
@kvloover
@kvloover Ай бұрын
The lock syntax has always felt off and out of place in c#. Glad it's now a specific lock object, and I get that it's still using the same syntax for migrating, but I hope we get a more flowing syntax. The semaphore felt even worse the first usage, just because the term felt so out of place. It doesn't feel like the proper type to use just because it doesn't really state the usage.
@Sergio_Loureiro
@Sergio_Loureiro Ай бұрын
~Nick Chapsas~ => *Nick Sharpsas*
@Eugene.Golubev
@Eugene.Golubev Ай бұрын
am I the only one, who've never used locking in my career as a web developer and always manage concurrency in DB?
@chralexNET
@chralexNET Ай бұрын
I think that is pretty normal for web developers, especially if you don't work on tooling or framework code. If what you do is just Create-Read-Update-Delete APIs and front-ends then you can pretty much just leave all that to the database as you said. Some examples of where I've used locking is for example to write rate limiters, for example when my backend needs to integrate with an external API. But it is also useful for example if you want to prevent a convoy of operations from e.g. hitting some external storage or cache service, to have a lock and for all requests to wait for the cache service to return a result, a lock can be used for that.
@fusedqyou
@fusedqyou Ай бұрын
This is a very common thing, especially when you want to efficiently handle multiple instances of the same work.
@Eugene.Golubev
@Eugene.Golubev Ай бұрын
@@chralexNET yeah, rate limiting is a good example I rarely write simple CRUDs. I usually write pretty complicated domain logic and optimistic concurrency solves most problems for me. I think, the more stateless your app is, the better
@diadetediotedio6918
@diadetediotedio6918 Ай бұрын
Well, the language is general purpose, it is not made specifically for you. I think it is alright for you to not require it, I myself almost never use locks nowadays for example (but I already used in the past for many things).
@devincarlson8866
@devincarlson8866 Ай бұрын
Even as a back end developer I hadn’t needed to use locks very frequently until recently. I had an API that ran background jobs to cache data into some singleton in-memory repositories from a DB for better performance since they were expensive queries. But I had a problem if an API query came in during the time that the cache was filling. I didn’t want to return an error, so I needed to await until the cache refill job had finished to read from the cache. So, I ended up using a SemaphoreSlim to do the job as Nick showed at the end here.
@kelton5020
@kelton5020 Ай бұрын
Seems dumb. Why not just make a MonitorSlim class and update the compiler to use that instead for locking or something. Why do we need a Lock object, it seems like an unnecessary change.
@amnesia3490
@amnesia3490 Ай бұрын
Would be nice if they address Task.Waits and UI Thread locking issues
@protox4
@protox4 Ай бұрын
That's not their problem, that's the programmer's problem. Don't use synchronous waits on asynchronous operations if you don't know what you're doing.
@ManInTheFridge
@ManInTheFridge Ай бұрын
What's this like compared to Java? Is Java more elegant with their approach to using multithreading?
@adambickford8720
@adambickford8720 11 күн бұрын
Java has had explicit locks for many, many years. ReadOnly, ReadWrite, Reentrant, etc. It also has the intrinsic object monitors like C#. If you don't have async support, you'd better have decent locks. Modern java tends to use function paradigms like share nothing/immutable state
@jonathansaindon788
@jonathansaindon788 Ай бұрын
Why not use Task.WhenAll?
@hellowill
@hellowill 9 күн бұрын
c# copying Java again after realising their way is wrong 🤣🤣🤣
@fusedqyou
@fusedqyou Ай бұрын
Here to say first before five others do.
@user-kc8ey3py3y
@user-kc8ey3py3y Ай бұрын
Theres a lot of bad advice and incorrect statements in this video. Love your stuff usually Nick but this isnt up your usual standard
@nickchapsas
@nickchapsas Ай бұрын
Mind explaining?
@user-kc8ey3py3y
@user-kc8ey3py3y Ай бұрын
Sure. I think a lot of others have mentioned this too but having a static lock object is a bad idea. Yes here in this video it's fine kind of but there's no need and teaches people the incorrect approach. In general the lock object should be the same life time as the resources it is guarding access to. Here (and most often) it's protecting instance data and so the lock object should be an instance field. If it's static you end up locking across all instances which is not needed when you are protecting data specific to one instance. (Hope that makes sense. KZfaq comments aren't the easiest place to voice this 😂). The other issue I spotted is the explanation of 'TryEnter' the timeout is not a limit to how long you can hold the lock. It's a limit for how long you'll wait to get it before it returns. Returning a Boolean indication of whether it successfully got the lock or not. Love you videos Nick and apologies if it came across rude. It's just I see a lot of these misconceptions around and you're usually a good source of correcting people
@jessegador
@jessegador Ай бұрын
The Lock cannot be used in the async because it is a ref struct.
@phizc
@phizc Ай бұрын
You can't use async code inside a lock block with the old approach either.
@urbanelemental3308
@urbanelemental3308 Ай бұрын
The simple trick is to avoid locking whenever possible.
@joeldickson5471
@joeldickson5471 Ай бұрын
Locks themselves aren't performemt. Better to avoid them as much as possible imo, single threaded programing and queues really helps here. But still nicer syntax in c# 9 for when you need the lock
@Rick104547
@Rick104547 Ай бұрын
That really depends on what you are trying to achieve. I wouldn't say locks themselves are slow as they do their work in 10's of nanoseconds. They are used in alot of places even if you are not aware of them.
@JW-lv1fm
@JW-lv1fm Ай бұрын
That's not great advice. They exist for a reason. Anyone who's looking into locking already knows that something special is happening and needs to learn about them. This is actually a useful mechanism for high performance code (so calling them slow just means they've been used improperly - how do you single thread a queue lookup when you are waiting on an external resource, like a cold file? You would be blocking the other hot files with that queue). There are many types of locks as well, which could be made more mainstream/have better documentation I suppose: Spinlock, Mutex, Monitor, Semaphore, ReaderWriterLockSlim
@dpduser
@dpduser Ай бұрын
I have seen that pattern for quite a long time. Using a static object means you are locking access to all objects, besides the one you are operating on. What you usually want (and no allocation is required) is to just call lock(this) { }.Only the target object is locked.
@JW-lv1fm
@JW-lv1fm Ай бұрын
lock(this) is bad standards, because this is public and anyone outside can unlock it. Another problem is that you don't indicate what logic you are locking. Sometimes when there are a lot of functions, its just nicer to say lock(SumVariableManipulationLock), in case you want to have more than 1 lock type for logic type, but now you partially indicate what its meant to keep threadsafe.
@dpduser
@dpduser Ай бұрын
@@JW-lv1fm Thanks for the comment. Regarding the "it is public" part, no, you cannot "unlock" it since (in this particular case) you could only invoke "Monitor.Exit()" from within the same thread that has acquired the lock. Regarding your second statemente, I absolutely agree with you: you may use "sub-locks" for more granular locking behaviour, but I would never make them static. In any case, my preference is going "lock-free" (when possible) via "interlocked" operations.
@louisfrancisco2171
@louisfrancisco2171 Ай бұрын
@@dpduser The problem is not that someone else can unlock it. It's that anybody can lock it.
@adambickford8720
@adambickford8720 11 күн бұрын
This was a known bad practice in java before C# stole it.
@MatinDevs
@MatinDevs Ай бұрын
They should add GPU-Based compilation
@andr6087
@andr6087 Ай бұрын
Thank you for support Ukraine!
The Pattern You MUST Learn in .NET
20:48
Nick Chapsas
Рет қаралды 84 М.
The New Option and Result Types of C#
15:05
Nick Chapsas
Рет қаралды 58 М.
الذرة أنقذت حياتي🌽😱
00:27
Cool Tool SHORTS Arabic
Рет қаралды 14 МЛН
👨‍🔧📐
00:43
Kan Andrey
Рет қаралды 10 МЛН
CHOCKY MILK.. 🤣 #shorts
00:20
Savage Vlogs
Рет қаралды 29 МЛН
🩷🩵VS👿
00:38
ISSEI / いっせい
Рет қаралды 21 МЛН
Settling the Biggest Await Async Debate in .NET
14:47
Nick Chapsas
Рет қаралды 142 М.
The World Depends on 60-Year-Old Code No One Knows Anymore
9:30
Coding with Dee
Рет қаралды 748 М.
Vim Motions & Tricks I Wish I Learned Sooner
9:25
Henry Misc
Рет қаралды 19 М.
Brutally honest advice for new .NET Web Developers
7:19
Ed Andersen
Рет қаралды 146 М.
The New .NET 9 HybridCache That You Must Upgrade To!
14:34
Nick Chapsas
Рет қаралды 50 М.
Why You Shouldn't Nest Your Code
8:30
CodeAesthetic
Рет қаралды 2,7 МЛН
Don't Use Polly in .NET Directly. Use this instead!
14:58
Nick Chapsas
Рет қаралды 57 М.
The 3 Laws of Writing Readable Code
5:28
Kantan Coding
Рет қаралды 483 М.
Don't throw exceptions in C#. Do this instead
18:13
Nick Chapsas
Рет қаралды 256 М.
Why I Chose Rust Over Zig
33:18
ThePrimeTime
Рет қаралды 158 М.
الذرة أنقذت حياتي🌽😱
00:27
Cool Tool SHORTS Arabic
Рет қаралды 14 МЛН