Just because you’re sharing data structures between threads doesn’t mean you have to use locks.
Over the years I’ve come across a few approaches that help coordinate work between threads without having to make anyone wait. Here are a couple of them.
WARNING: I stopped using these patterns because they are easy to misunderstand and misuse, which can lead to random hard-to-diagnose bugs. If you use these patterns, you’re not helping the next develper understand the code better or avoid mistakes. You have been warned.