Abort script that renders frames
To stop the loop you can install your own handler for the SIGINT signal which is executed by the main thread. (see signal module)

The rendering of the current frame will not abort.

import bpy
import signal

abort = None

def hndl(signum, frame):
    global abort
    abort = True
    print("\nAbort")
    #uncomment to call the default handler
    #raising the KeyboardInterruption exception
    #signal.default_int_handler(signum, frame)

def run():
    global abort
    signal.signal(signal.SIGINT, hndl)
    count = 0
    abort = False
    while not abort and count &lt; 10:
        count += 1
        print(count, abort)
        bpy.ops.render.render()

def reset():   
    signal.signal(
        signal.SIGINT, 
        signal.default_int_handler
        )

if __name__== "__main__":
    run()
    reset()