Generally speaking, multithreaded programming is one of the most difficult topics to master as a developer. As human beings, we are intrinsically used to thinking sequentially and many programming languages (like Pascal) have been designed to be used in an imperative, synchronous, deterministic paradigm. We usually design our code thinking in terms of a sequence and making the assumption that steps are not overlapping (and that they follow the first-in-first-out approach, for example).
Let's try to use a real-world example of a sequential operation that we feel is naturally sequential and where the need for synchronization is completely transparent (as we are used to automatically managing underlying complexity as human beings). Think about serving yourself a glass of water. The sequence seems pretty straightforward:
- Put the glass on the table.
- Open the bottle.
- Pour water into the glass.
- Close the bottle.
- Get the glass.
- Drink the glass of...