That's the way GNU/Linux and other multitasking systems work, they share the processor among the running processes,
dot won't have 99%, but 100% during 99% of the time. Each process dominates the processor for a certain period of time.
This is handled by schedulers (linux has several schedulers, some just employ the usual strategy, some try to give more time to user interfaces, and so on).
Now, in your case, the problem was — probably — that
dot wasn't taking a lot of processor time, but lots of memory. And when a program uses too much memory, there is thrashing, which is exactly a process that makes the system freeze, not because
dot is doing a lot, but because the kernel has to move memory pages back and forth between the disk (swap partition) and the system memory.
dot was just taking 99% of CPU time, chances are that changing to a text terminal would be almost immediate, what happens is that the kernel has to move
dot stuff out of memory so it can put
X back in memory so that
X can see the keys you just hit and move to the text terminal, then the kernel has to move
X out of memory for
dot which is still running, and then also move
dot out to move the text terminal processes (maybe just
login?) back in memory. (If this looks messy, it's not just because the example is messy — the reality is this messy.)
An example is if you log in the text terminal, you may be able to just hit keys, hit backspace, and it will happily happen real-time, but if you do something as simple as running a small tool like
ps, it will "freeze" for a while because it has to free memory to load
ps (and it also has to wait in the disk I/O queue, which is being heavily used to move data to and from memory, until it is able to request
ps from the filesystem).