This does not work when you can have threads executing arbitrary native code, that can do some non-GC related work for essentially unbounded time, which is certainly case with .NET. In JVM any native code tends to be prepared to cope with this somehow, but .NET is explicitly designed to be able to seamlessly interoperate with random COM and legacy native libraries, so you cannot guarantee that such native code will get back to GC safe point in any bounded amount of time.
Edit: you can do stop-the-world GC at any point of program whan you scan stack conservatively, GC-safe points are only needed for precise scanning of stack and registers, so this is problem only when you want to be fully precise. Fully precise GC is certainly better when it is possible, but conservative scan works mostly well enough.