I think the reason for this is dubious implementation of background processes. Instead of checking which processes are background process and foreground processes, and only sending SIGINT to the foreground processes, the background processes are told to ignore SIGINT, and the signal is sent to all processes when ^C is received.
You can clear this by putting signal(SIGINT, SIG_DFL) in the beginning of your program, if you want it to behave like a regular foreground process, despite being run in the background.
This is a quite poorly documented fact, that took major hair-pulling to deduce. There are two lessons to be learned:
- Don't make assumptions about the standard behavior of anything.
- Document obscure behavior.
Thus endeth the frustrated rant.