At its core, the halting problem is a problem of cycle detection. The question it aims to answer is: "Does this program terminate, or end up in an infinite loop/recursion?" The problem assumes all program input is already known. Of course, if your loop depends on the user pressing Y/N, you can never figure out if the program will halt unless you are a clairvoyant.
There are proofs that the halting problem can not be solved, and I won't reproduce them here. Rather, I am going to rephrase the question for real hardware, starting from first principles. It's a subtle yet important distinction that Turing machines are infinite, and real computers are not.
First, lets realize that we can definitely solve the halting problem for some programs: while(1){}
will obviously never halt. So the halting problem is not completely unsolvable for special cases.
For the purposes of this article I will assume a von Neumann architecture so we have unified memory. We implant all user input into the memory before the program runs, and we do not externally modify the memory during runtime. In these conditions, we use a cycle detection algorithm like "Floyds Tortoise and Hare" to detect if a state occurs multiple times.
Why does this detect loops? Because to loop, the CPU's program counter must be equal at two points in time: it executes the same code. Additionally, the rest of the state/memory must also be equal at these points in time, because that would mean there was no progression with regards to the last time the program was at this point. And if there is a repetition with no progression, and no external effects, the system will keep repeating, and thus we can say the system will not halt.
For instance, the while(1){}
will likely translate to some sort of assembly of the form
x:
goto x;
Where the CPU instruction pointer is continually reset to point to x
. The rest of the memory also stays equal.
A pathological case is a for loop:
for (int i=0; 1; i++){}
This will do nothing forever, but the memory keeps changing because i
continually gets incremented. Due to overflow, i
will be the same at 2 points in time however, so we can still detect a cycle, it will just take a long time.
In general, the "fuller" a loop is with the more memory locations touched, the harder this analasys becomes. The cycle detection algorithm is bounded in space, so that's not an issue, only time is.
If we observe the program exiting before the cycle detection found a cycle we can say that the program halts. Sadly it seems we can not determine this reliably a priori.
To see a proof of concept, implemented in C: /halt.c