What are the causes of Arduino lockup?
Most Arduino projects involve sensing the physical world or controlling the physical world (hopefully with some feed back).  When sensing the physical world, it is best to add extra code to protect the project from locking up.  And then, even more code concerned with what to do when the unlikely happens.  Unfortunately, many projects leave out this extra code.  Reasons vary:


The project is a prototype and the effort is thought necessary.
There is no time in the schedule to create this "extra code".
The unexpected event is thought to be an impossible situation.
There is no room left to add code that is not expected to run.


As an example:

A bicycle is outfitted with an Arduio base digital speedometer.  Speed is calculated based on the period of a wheel mounted magnet passing a frame mounted Hall Effect switch.  It works as long as the bicycle is moving at a reasonable speed.  However, the program does not take into account what happens if the bicycle is not moving.  If the magnet does not pass the Hall Effect switch.  The program's period counter continues to count up.  Eventually the watch dog timer reset the program.  Over and over again.

Approaches to avoid lockup or to avoid using the watch dog timer:


Place all "non-blocking" polling in an infinite loop which also check the elapsed time.  Consider the amount of time allowed to make a successful reading.  If that time expires consider a good course for the program to follow.  For instance a warning to the user or a default value when the measured value is unavailable.
Use interrupts.  That is, use the above method, but relay on external signal changes to generate interrupts to set values and / or flags.  This is a good (however more complex) alternative if the external signal occurs too fast for "non-blocking" polling.