A Comparison of Dynamic Detection and Static Prevention in Solving Synchronization Problems

Josh Cates

Dynamic detection and static prevention are two methods of correcting synchronization problems in multi-threaded programs. Dynamic detection is performed at runtime, while static prevention is performed before compilation. This difference is echoed by the advantages and disadvantages of each method.

Dynamic detection detects errors only for the execution path chosen at runtime. This is a disadvantage, because a program must be run many times to test all code paths. In contrast, a static preventor is more thorough; it tests all possible code paths at once.

By exploiting runtime information, a dynamic detector can accurately determine which locks guard which data. A lack of this information often blinds a static preventor. For example, when a lock is acquired through a pointer a static preventor does not know which lock the pointer references. Instead, a static preventor must rely on heuristics, assumptions, and explicit user source code annotations to determine which locks guard which data. This is cumbersome and inaccurate.

A static preventor would benefit from a high-level language which directly supports multi-threading. Such a language would allow locking semantics to be more easily inferred--and the accuracy problem of static preventors to be ameliorated.

A dynamic detector is more useful as an afterthought to coding. After a program is written, bugs may be discovered. A static preventor is not suitable to correct these bugs, because using a static preventor requires adding time-consuming annotations to the source code.

To fix synchronization problems, static and dynamic checkers offer complementary opportunities: where one method excels the other is often lacking. The advantages of each method can be leveraged by using a combination of both methods. This can instill a degree of confidence that neither method alone could provide.