Synchronization allows you to control program flow and access to shared data for concurrently executing threads.
The three synchronization models are mutex locks, condition variables, and semaphores.
Mutex locks allow only one thread at a time to execute a specific section of code, or to access specific data.
Counting semaphores typically coordinate access to resources. The count is the limit on how many threads can have access to a semaphore. When the count is reached, the semaphore blocks.