What are kernel synchronization primitives such as spinlocks and mutexes, and when would you use each?