It will still leave resources in unknown and possibly inconsistent state, moreover you need to use `pthread_cleanup_push` to register everything that may need to be done to clean up the thread... for languages with RAII this basically means the destructor of every local variable, which isn't really reasonable, so you end up with ton of code where it won't work. You can claim it's "standard", but de-facto it really isn't and most code is not "well-formed" from its point of view.
Cancellation is just an exception, so destructors work automatically. Any implementation of a language that uses RAII without integrating cancellation into it is fundamentally broken and should be avoided at all costs. `pthread_cleanup_push` (or `__attribute__((cleanup))` is only needed if you're implementing it by hand.
Since the set of functions that can be cancelled is documented (and pretty obvious - roughly, any blocking function but notably excluding mutex functions), there's no "unknown" involved. At most there is "I insisted on writing C but refused to take the effort to make my code correct in a threaded environment."
Notably, `malloc` is not a cancellation point so this all is much easier to deal with than signals.