你的问题的简短回答是肯定的。即使他们附加的进程正忙于进行计算或某种 io/等待,它们也能工作。唯一的限制是该过程不会发生变化并且不会SIGALRM自行玩耍,这会导致问题。当信号到达时,进程/线程的正常执行被挂起并调用信号处理程序。这就是信号处理的全部思想以及它为什么被称为asynchronous.
你的问题更长的答案是否定的。您不希望通过信号处理程序机制实现进度报告,因为您可以在信号处理程序中使用的 API 非常有限。确切地说,您提到的示例是错误的,因为它使用了fprintf(3). 正如在其中一个答复中所述,信号是异步的。这意味着如果信号在主代码调用的中间到达malloc(3),并且你的代码malloc(3)也调用(你永远不知道,printf(3)可能会调用malloc(3)缓冲和其他需求),那么你将破坏 malloc 自己的内部数据结构并导致程序出错。您甚至可能在调用自己的非异步安全函数时遇到问题。您有一个可以在信号处理程序中调用的安全函数列表,您可以在man 7 signal下Async-signal-safe functions。alarm(3)所以是的,从技术上讲,只要你愿意使用这个简化的 API,你就可以实现进度报告,这就是我不会这样做的原因,除非程序是单线程设计的,除非我真的没有办法将进度报告代码视为受未来增强的影响,这将使其难以在信号处理程序中编写。
关于您的示例的另一个问题是它alarm(2)不接受亚秒级参数,上面的示例应该完全编译失败,或者至少显示了一些关于该事实的警告。
对于微秒分辨率,您可以使用setitimer(2)如前所述ITIMER_REAL。
对于 Linux 上的纳秒级分辨率,您可以使用timer_create(2), CLOCK_REALTIME,SIGEV_SIGNAL以及timer_settime(2)更多功能。  
这是一些示例代码。请注意,这使用了我自己的错误处理宏。你可以在这个项目demos-linux中看到它处于可编译状态
#include <signal.h> // for signal(2), SIG_ERR
#include <unistd.h> // for alarm(2), write(2)
#include <stdlib.h> // for EXIT_SUCCESS
#include <err_utils.h>  // for CHECK_NOT_M1(), CHECK_NOT_SIGT()
#include <stdio.h>  // for snprintf(3), STDERR_FILENO
/*
 * This is an example of doing progress reports via the SIGALRM signal every second.
 * The main code does a tight calculation loop and the progress reporting to stderr
 * (file descriptor 2) is done via the alarm signal handler.
 */
/*
 * The variables are global to allow the signal handler to access them easily
 * You DONT need to initialize them to 0 since that is the default.
 * The 'volatile' on i is *critical* since it will be accessed asynchronously
 * and the compiler needs to know not to put it in a register since that
 * will mean that we cannot report it's value correctly from the signal
 * handler.
 */
volatile unsigned long i;
/*
 * Remember that this is a signal handler and calls to fprintf(3) or the like
 * are forbidden so we are forced to use async-safe function (see man 7 signal).
 * That is the reason for the cumbersome code. Hopefully snprintf(3) is safe enough
 * to use.
 */
static void handler(int sig) {
    // we have to reschedule the SIGALRM every time since the alarm(2)
    // is a one time deal.
    CHECK_NOT_SIGT(signal(SIGALRM, handler), SIG_ERR);
    // no error code from alarm(2)
    alarm(1);
    char buf[100];
    int len=snprintf(buf, sizeof(buf), "did [%ld] units of work...\n", i);
    CHECK_NOT_M1(write(STDERR_FILENO, buf, len));
}
int main(int argc, char** argv, char** envp) {
    CHECK_NOT_SIGT(signal(SIGALRM, handler), SIG_ERR);
    // no error code from alarm(2)
    alarm(1);
    // a very long calculation
    while(true) {
        /* Do some real work here */
        i++;
    }
    return EXIT_SUCCESS;
}