Well to report back, I’ve discovered locking does have an overhead, a serious overhead.
If you have a for loop that loops over 1000 values, and you apply the locking inside the for loop, you will encounter serious slow downs. It is necessary to lock the entire for loop. You actually want to use lock as little as you possibly can.
Given what I’ve found, I would actually say you want to avoid doing more than a single lock command in an Update loop, or maybe two.
Store all the data you need to update from the multithreaded variable into temporary variable, reading into the temporary variable while locked. Then unlock it, alter the temporary variable, and then lock again, read it back into the multithreaded variable.
And actually, if one thread is very performance critical, you may purposely want to over-lock it. Meaning, just lock a huge chunk of the Update function, even if the lock over extends it’s usage in some instance. Because if the update function has to lock a variable, do something else, then regain the lock, it is possible that regaining that lock could cause a pause. This does happen, and it was a big issue I found. The more locks you have in an update function, the greater the chance your update function is going to jitter and have to pause and wait.
For example, in my game I am locking a variable in my FixedUpdate and am then locking the same variable being updated by a function on another thread. The function on the other thread is performance critical but, since it doesn’t have immediate visual feedback, it can skip, jump and jitter without issues.
So what I have I have done is, in my secondary thread function, I lock and unlock the needed variable a bunch of times. This does make the secondary thread function go slower, but it also makes it so that the FixedUpdate function has greater possibly of being able to grab the lock when it needs it, and not cause a jitter. The fixedupdate then has just one single lock, and it is a large lock, which I am sure caused my secondary thread function to jitter. But again, the secondary thread function has no visual feedback, so it can jitter and skip without notice. This setup I have found to give the best performance, because it basically gives prevelance to the lock in the fixedupdate. The fixedupdate has more opportunities to grab the lock, and it holds and maintains the lock for longer. This gives me no noticeable drop in performance.
Is this a good design pattern, or is there a better way to do this?
And you know I’m still not completely sold on whether or not this is necessary. I know all the documentation says to do it I think that documentation was written with a different type of application in mind. My game seems to run just fine without it, and I haven’t seen lack of locks cause any issue at all. The data that is being locked and unlocked is not exactly super critical, it gets updated every frame, so if some erroneous data did get read in, the player wouldn’t even notice. I’ve been researching and I have found the only real issue with not using locks is a ‘race condition’ where one thread might alter the data, when another thread is doing something to the data and expecting a result. But my code wouldn’t have any issues with a race condition. The multithreaded variable is really just a back and forth communication variable, one thread spits data into it, the other thread reads it. No race condition could occur. And as far as what I understand at a deep internal level a CPU will not be editing and reading the same piece of memory at the same time. So even if I sent a call to read a block of memory, and write to a block of memory at the same time, at a deep internal level, one of these operations will occur one after the other, they can’t actually occur at the same time. Which in my instance, it actually doesn’t matter which one occurs first or second, because it updates so fast you couldn’t even notice.
So really… I am thinking I don’t need to use Locks. Is there something I may have missed? Anyone who knows more on this, any critique on my thought process would be much appreciated.