Tips for Designing Asynchronous Programs
- When designing multithreaded applications, it is important to remember that one cannot assume any order of execution with respect to other threads.
- Any such order must be explicitly established using the synchronization mechanisms discussed above: mutexes, condition variables, and joins.
- In many thread libraries, threads are switched at semi-deterministic intervals.
- Such libraries ( slightly asynchronous libraries) are more forgiving of synchronization errors in programs.
- On the other hand, kernel threads (threads supported by the kernel) and threads scheduled on multiple processors are less forgiving.
- The programmer must therefore not make any assumptions regarding the level of asynchrony in the threads library.
- The following rules of thumb which help minimize the errors in threaded programs are recommended.
- Set up all the requirements for a thread before actually creating the thread. This includes
- initializing the data,
- setting thread attributes,
- thread priorities,
- mutex-attributes, etc.
- Once you create a thread, it is possible that the newly created thread actually runs to completion before the creating thread gets scheduled again.
- When there is a producer-consumer relation between two threads for certain data items,
- At the producer end, make sure the data is placed before it is consumed and that intermediate buffers are guaranteed to not overflow.
- At the consumer end, make sure that the data lasts at least until all potential consumers have consumed the data.
- This is particularly relevant for stack variables.
- Where possible, define and use group synchronizations and data replication.
- This can improve program performance significantly.
- While these simple tips provide guidelines for writing error-free threaded programs, extreme caution must be taken to avoid race conditions and parallel overheads associated with synchronization.
Cem Ozdogan
2010-12-27