Another issue that arises when using interrupts is how to safely update data structures in use between the ISR and the threads in the application.
Two important characteristics are worth repeating:
This means that you can't use thread-level synchronization (such as mutexes, condvars, etc.) in an ISR.
Because the ISR runs at a higher priority than any software thread, it's up to the thread to protect itself against any preemption caused by the ISR. Therefore, the thread should issue InterruptLock() and InterruptUnlock() calls around any critical data-manipulation operations. Since these calls effectively turn off interrupts, the thread should keep the data-manipulation operations to a bare minimum.
With SMP, there's an additional consideration: one processor could be running the ISR, and another processor could be running a thread related to the ISR. On an SMP system, these functions take and release a spinlock to add synchronization across cores. Again, using these functions on a non-SMP system is safe; they'll work just like InterruptDisable() and InterruptEnable(), albeit with an insignificantly small performance penalty.
Another solution that can be used in some cases to at least guarantee atomic accesses to data elements is to use the atomic_*() function calls; see Atomic operations.
Variables accessed in both an ISR and normal thread processing must be marked as volatile.