Thinker

A thinker is an instance of a large number of diverse structures in the Doom engine which are used to implement per-tic scheduled actions within the game world. Thinkers are linked into a global double-linked list which is iterated down once per tic, giving each object a turn at running its logic for that time slice. This is a very basic implementation of a cooperative multitasking system.

Types of thinkers
The following types of objects in the game world are implemented as thinkers in the original game engine:
 * Moving floors and ceilings: doors, lifts, crushing ceilings, etc.
 * Map objects
 * Sector lighting effects

Hexen adds many new types of thinkers in its customization of the Doom engine:
 * ACS scripts
 * Waggling floor effects
 * Pillars
 * Earthquakes
 * Polyobjects

Source ports may significantly expand the scope of thinkers to include new effects.

Pseudo-inheritance
Though Doom was written in the C language, which is not inherently object oriented, thinkers utilize a technique common in C programming called pseudo-inheritance. Every type of structure which behaves as a thinker contains as the first member in its definition a thinker_t instance. This allows pointers to any of the various descendant types, such as mobj_t, to be cast to and from a pointer to thinker_t. Each thinker contains a pointer to a function to be executed every tic that is specific to its derived type, such as P_MobjThinker for mobj_t. Testing the value of this function to determine the true type of a thinker_t instance is used as a rudimentary form of run-time type information.

As a result of the architectural similarity, most C++ source ports translate this idiom into a full class hierarchy - this is the case for both ZDoom and the Eternity Engine.

Problems
Doom's thinker list is not without problems. The original engine does not implement any form of reference counting, and therefore it is possible for objects which have been removed from the list and freed to be referenced or modified afterward, resulting in arbitrary or "undefined" behavior, which may lead to corruption of other thinkers or the thinker list itself, and may eventually lead to a crash. Lost souls are particularly prone to issues related to this problem because when they become invisible at the end of their death sequence, they free themselves, causing any monsters still angry at them to possibly continue to reference invalid memory.

The Boom source port was the first implementation to correct this flaw via addition of reference counting. Some later ports have replaced the reference counting scheme with full-scale garbage collection.