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.
@zpa894 ай бұрын
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
@bodziotoja4 ай бұрын
@@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.
@nocturne63204 ай бұрын
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.
@zpa894 ай бұрын
@@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.
@martinprohn24334 ай бұрын
@@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.
@andreydeev43424 ай бұрын
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.
@code89863 ай бұрын
+1 for lock-free techniques
@jamesreynolds31674 ай бұрын
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.
@LasseVågsætherKarlsen4 ай бұрын
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.
@billy65bob4 ай бұрын
Could just be an implementation detail?
@MrWuffels2 ай бұрын
@@billy65bob well this makes hell of a difference and a programmer using the lock should know that.
@urbanelemental33089 күн бұрын
Just updated my threading/sync libraries to support this: Open.Threading.ReadWrite and Open.Threading You are right about benchmarking, it's hard to see a difference.
@AL12rs4 ай бұрын
I'd love to hear more about best practices and libraries for Async locking
@mynameisshadywhat4 ай бұрын
Had to double check when this video was posted 4:45 you say C# 9 instead of .NET 9 😂
@modernkennnern4 ай бұрын
There's some talk about `await lock` similar to `await foreach` to allow asynchronous locking
@hellowill3 ай бұрын
locks belong to threads so async lock doesn't really make sense IMO. Should be a semaphore.
@anonymous491254 ай бұрын
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.
@code89863 ай бұрын
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.
@anonymous491253 ай бұрын
@@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.
@julianocs874 ай бұрын
I had to check the date of the video when you mentioned C# 9 instead of .NET 9.
@vacantbill4 ай бұрын
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.
@silentdebugger4 ай бұрын
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.
@leowong98854 ай бұрын
Brings back memory of intro class to OS - mutex, p & v, monitor, critical session... Thanks for introducing the new lock mechanism.
@TheTim4664 ай бұрын
critical section*
@configadd4 ай бұрын
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?
@Kitulous4 ай бұрын
not all methods are async, so locking with the Lock class may still be useful
@fusedqyou4 ай бұрын
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.
@andersborum92674 ай бұрын
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.
@duffscs4 ай бұрын
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
@georgepagotelis4 ай бұрын
Especially since if you enable true in the project file couldn't it just improve the code if it's the same?
@WileeRunner424 ай бұрын
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.
@ArcaneEye4 ай бұрын
isn't that just a semaphore?
@trexug65774 ай бұрын
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.
@vbjay4 ай бұрын
Just wanted to point out the fix of using interlocked to do the sum without locking. But the point was the locking.
@the-niker4 ай бұрын
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.
@duffscs4 ай бұрын
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
@davidantolingonzalez49294 ай бұрын
@@duffscsSemaphoreSlim works in Wasm
@GlebAOsokin4 ай бұрын
I've read somewhere, that acquiring a SemaphoreSlim is ~10x slower than acquiring a simple lock...
@the-niker4 ай бұрын
@@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.
@GlebAOsokin4 ай бұрын
@@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.
@Tesfamichael.G4 ай бұрын
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
@diligencehumility69714 ай бұрын
Would have been nice with a performance comparison
@exemory4 ай бұрын
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
@phizc4 ай бұрын
How would that demonstrate the new Lock class?
@mamicatatibe4 ай бұрын
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)
@phizc4 ай бұрын
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(); }
@mamicatatibe4 ай бұрын
@@phizc thanks, for some reason I always thought it makes more sense for this to also be within the try block
@louisfrancisco21714 ай бұрын
@@mamicatatibe If the variable initialization is inside the try block, then the Dispose method could be called on an uninitialized variable.
@code89863 ай бұрын
@@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?
@louisfrancisco21713 ай бұрын
@@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.
@MayronWoW4 ай бұрын
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?
@nickchapsas4 ай бұрын
The lock scope will be created for you on the boundaries of the lock if you lock a lock type
@chralexNET4 ай бұрын
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.
@georgepagotelis4 ай бұрын
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.
@phizc4 ай бұрын
You could use an analyzer to create an error if lock is used with anything other than a Lock object.
@heischono49173 ай бұрын
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?
@dimonasdf3 ай бұрын
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 :)
@rikudouensof4 ай бұрын
Have not used lock before
@code89863 ай бұрын
You’ve been lucky :)
@shanehebert3964 ай бұрын
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).
@rmcgraw79433 ай бұрын
SpinWait is your friend.
@adambickford87203 ай бұрын
Until it isnt
@rmcgraw79432 ай бұрын
@@adambickford8720LOL, yeah, it sometimes makes you AwaitOnComplete, even UnsafeAwaitOnComplete
@dusrdev4 ай бұрын
Is it supposed to replace only the simple lock on object, or types like the readerwriterlockslim as well?
@protox44 ай бұрын
The former.
@mikol01584 ай бұрын
Why using lock when you have semaphore slim?
@tarsala19954 ай бұрын
`await` in `lock` is disallowed due to possible change of thread that is executing the code. Doubtful that MS will change that.
@fusedqyou4 ай бұрын
.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.
@shahzaibhassan27774 ай бұрын
I saw Rust's multi threading much easier to make sense of
@victor18824 ай бұрын
@@shahzaibhassan2777 until async comes into the picture
@keyser4564 ай бұрын
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?
@Rick1045474 ай бұрын
How is .NET weird with thread safety? If anything its pretty standard.
@_grigoryta4 ай бұрын
1:09 Paralyzed loop? Didn't know programming concepts could have disabilities. What a diverse world we live in
@artemisDev4 ай бұрын
When there's a deadlock in your parallelized loop.
@foxgodess94 ай бұрын
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
@zglmorph4 ай бұрын
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.
@mikewright28584 ай бұрын
How is this better than the ReaderWriterLock?
@jongeduard4 ай бұрын
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.
@DaminGamerMC4 ай бұрын
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?
@vasiliychernov21234 ай бұрын
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.
@DaminGamerMC4 ай бұрын
@@vasiliychernov2123 Thanks, put in that way makes a lot of sense.
@phizc4 ай бұрын
In short it's a race condition.
@protox44 ай бұрын
9:54 I wrote one!
@lordmetzgermeister4 ай бұрын
FYI you talk about new locks in C# 9 but it should be .NET 9
@eugene50964 ай бұрын
Not sure if this make a lot of difference if i would use Monitor explicitly
@pedrofpsimoes4 ай бұрын
I was happy for a while, but then it is the same hassle when using it with async-await LoL 😂
@YukonianOrangutangInSpace4 ай бұрын
Very informative, thank you! Excited for this.
@mattfbk4 ай бұрын
ReaderWriterLockSlim
@Tony-dp1rl4 ай бұрын
I can't think of a rational reason to lock an await call.
@marvinalone3 ай бұрын
C#9 or .Net 9 ?
@code89863 ай бұрын
You’re right, he should’ve said .NET 9.
@Michael.SMarsh4 ай бұрын
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
@jjxtra3 ай бұрын
Interlocked.*
@kvloover4 ай бұрын
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.
@amnesia34904 ай бұрын
Would be nice if they address Task.Waits and UI Thread locking issues
@protox44 ай бұрын
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.
@cj82-h1y4 ай бұрын
Why didn't they decide to support async code? - That's a disappointment
@cocoscacao61024 ай бұрын
Genuine question... What's the point of locking? It's just sequential code with extra steps...
@nickchapsas4 ай бұрын
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
@andersborum92674 ай бұрын
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).
@cocoscacao61024 ай бұрын
@@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...
@sealsharp4 ай бұрын
Queues made for concurrency hide the lock away from you.
@diadetediotedio69184 ай бұрын
@@cocoscacao6102 If you are implementing the queue processing you would use it.
@jessegador4 ай бұрын
The Lock cannot be used in the async because it is a ref struct.
@phizc4 ай бұрын
You can't use async code inside a lock block with the old approach either.
@ManInTheFridge4 ай бұрын
What's this like compared to Java? Is Java more elegant with their approach to using multithreading?
@adambickford87203 ай бұрын
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
@Sergio_Loureiro4 ай бұрын
~Nick Chapsas~ => *Nick Sharpsas*
@Eugene.Golubev4 ай бұрын
am I the only one, who've never used locking in my career as a web developer and always manage concurrency in DB?
@chralexNET4 ай бұрын
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.
@fusedqyou4 ай бұрын
This is a very common thing, especially when you want to efficiently handle multiple instances of the same work.
@Eugene.Golubev4 ай бұрын
@@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
@diadetediotedio69184 ай бұрын
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).
@devincarlson88664 ай бұрын
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.
@jonathansaindon7884 ай бұрын
Why not use Task.WhenAll?
@clhoover44 ай бұрын
Don't use static, ever, all instances will have the same lock
@user-zz6fk8bc8u4 ай бұрын
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.
@clhoover44 ай бұрын
@@user-zz6fk8bc8u The challenge from my experience is static variables creates a tight coupling, impacting testing, refactoring, evolution of the system, thread safety, etc...
@ilyahryapko4 ай бұрын
@@user-zz6fk8bc8u can you elaborate please?
@RiversJ3 ай бұрын
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.
@GustavoHennig4 ай бұрын
The result is always different in kzbin.info/www/bejne/mGXWhpiYfbSHn5Y 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.
@davilinkicefire4 ай бұрын
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-lv1fm4 ай бұрын
@@davilinkicefire Factorial is multiplicative, hes doing additive. 1225 is 0 through 49 added.
@rauberhotzenplotz77224 ай бұрын
Parallel.For is blocking
@davilinkicefire4 ай бұрын
@@JW-lv1fm You right, my bad
@GustavoHennig4 ай бұрын
@@rauberhotzenplotz7722 🤦♂You're right, it's blocking, I missed that.
@fusedqyou4 ай бұрын
Here to say first before five others do.
@kelton50204 ай бұрын
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.
@urbanelemental33084 ай бұрын
The simple trick is to avoid locking whenever possible.
@dpduser4 ай бұрын
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-lv1fm4 ай бұрын
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.
@dpduser4 ай бұрын
@@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.
@louisfrancisco21714 ай бұрын
@@dpduser The problem is not that someone else can unlock it. It's that anybody can lock it.
@adambickford87203 ай бұрын
This was a known bad practice in java before C# stole it.
@DaveQuinn-k6x4 ай бұрын
Theres a lot of bad advice and incorrect statements in this video. Love your stuff usually Nick but this isnt up your usual standard
@nickchapsas4 ай бұрын
Mind explaining?
@DaveQuinn-k6x4 ай бұрын
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. KZbin 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
@hellowill3 ай бұрын
c# copying Java again after realising their way is wrong 🤣🤣🤣