我有一个父进程和两个孩子.父进程只创建两个孩子,一个读者和一个计数器,并等待它的死亡.孩子们做了以下事情.
第一个孩子(读者):
打开文件,
读一条线,
向第二个孩子发送信号(SIGUSR1),
等待第二个孩子的信号,
如果我们可以读另一行,请转到2,否则杀死第二个孩子.
第二个孩子(柜台):
等待读者的信号(SIGUSR1),
计算线长,
向读者发送信号并转到1.
我等待来自另一个进程的信号时遇到麻烦.在调用pause()
函数之前可以接收信号,即可以永久阻止进程.我还试图用sigprocmask()
,sigsuspend()
和sigwaitinfo()
,但它不能正常工作.
#include#include #include #include #include #include #include #include #include enum { MAX_LEN = 16 }; void handler(int signo) { // do nothing } int main(int argc, const char * argv[]) { sigset_t ss; sigemptyset(&ss); sigaddset(&ss, SIGUSR1); // handle SIGUSR1 signal(SIGUSR1, handler); // shared memory for file line char *data = mmap(NULL, MAX_LEN, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); pid_t *pid_counter = mmap(NULL, sizeof(*pid_counter), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); pid_t pid_reader; if (!(pid_reader = fork())) { sigprocmask(SIG_BLOCK, &ss, NULL); printf("READER: waiting signal from COUNTER\n"); fflush(stdout); sigwaitinfo(&ss, NULL); sigprocmask(SIG_UNBLOCK, &ss, NULL); printf("READER: got signal\n"); fflush(stdout); printf("READER: opening file\n"); fflush(stdout); FILE *f = fopen(argv[1], "r"); while (fgets(data, MAX_LEN, f) > 0) { printf("READER: reading line and waiting signal from COUNTER\n"); fflush(stdout); sigprocmask(SIG_BLOCK, &ss, NULL); kill(*pid_counter, SIGUSR1); sigwaitinfo(&ss, NULL); sigprocmask(SIG_UNBLOCK, &ss, NULL); printf("READER: got signal\n"); fflush(stdout); } printf("READER: closing file and killing COUNTER\n"); fflush(stdout); fclose(f); kill(*pid_counter, SIGTERM); _exit(0); } if (!(*pid_counter = fork())) { sleep(1); printf("COUNTER: send signal to READER that COUNTER is ready\n"); fflush(stdout); while (1) { sigprocmask(SIG_BLOCK, &ss, NULL); kill(pid_reader, SIGUSR1); printf("COUNTER: waiting signal from READER\n"); fflush(stdout); sigwaitinfo(&ss, NULL); sigprocmask(SIG_UNBLOCK, &ss, NULL); printf("COUNTER: got signal\n"); fflush(stdout); printf("%d\n", strlen(data)); fflush(stdout); } } wait(NULL); wait(NULL); return 0; }
对于此代码,我可以得到以下序列:
$ gcc -o prog prog.c && ./prog input.dat READER: waiting signal from COUNTER COUNTER: send signal to READER that COUNTER is ready COUNTER: waiting signal from READER READER: got signal READER: opening file READER: reading line and waiting signal from COUNTER READER: got signal READER: reading line and waiting signal from COUNTER READER: got signal READER: reading line and waiting signal from COUNTER READER: got signal READER: reading line and waiting signal from COUNTER READER: got signal READER: reading line and waiting signal from COUNTER READER: got signal READER: reading line and waiting signal from COUNTER READER: got signal READER: closing file and killing COUNTER
为什么计数器不写"有信号"?我如何同步发送和接收信号?(我知道其他IPC方法,但我需要通过信号进行同步.)
这里有一些明显的问题.
实际导致您的问题的是:
if (!(*pid_counter = fork())) {
记住(1)pid_counter
指向共享内存; (2)每次调用时fork()
返回两次.当它在子节点中返回时,它将设置*pid_counter
为0
,但当它在父节点中返回时,它将设置*pid_counter
为子节点的PID.你无法预测哪一个会先发生.在您的情况下实际发生的是它最终设置为0
,因此kill
读取器进程中的所有调用都向您的进程组中的每个进程发送信号,因此读取器和计数器都同时获取它们.这导致同步失败,因为两个进程同时返回sigwaitinfo()
.在阅读器中,您应该只发送SIGUSR1
到计数器进程.
您需要做的是将其更改为:
pid_t temp_pid if ( !(temp_pid = fork()) ) { *pid_counter = getpid();
其他要点:
sigprocmask()
保留在fork()
调用之间,所以你应该在之前设置它一次fork()
.你永远不需要在你的情况下取消阻止,不应该.
SIGUSR1
如果你正在调用sigwaitinfo()
它,就没有必要(并且可以说最好不要)建立一个处理程序.
strlen()
返回类型size_t
,因此您的printf()
格式说明符应该是%zu
,而不是%d
.
你所有的电话fflush(stdout)
,虽然无害,但在这里是多余的.
你几乎没有检查系统调用的任何回报.这不仅仅适用于生产代码 - 如果您的程序无法运行,首先要做的就是验证您是否检查了所有系统调用是否成功,因为它可能无法正常工作的原因是因为其中一个调用是失败,也许是因为你传递了不好的信息.在测试程序时检查是否成功更为重要,同样重要.
无论如何,这是你的程序的工作版本:
#include#include #include #include #include #include #include #include #include enum { MAX_LEN = 16 }; int main(int argc, const char * argv[]) { if ( argc != 2 ) { fprintf(stderr, "Enter one argument, and one argument only.\n"); return EXIT_FAILURE; } // shared memory for file line char *data = mmap(NULL, MAX_LEN, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); if ( data == MAP_FAILED ) { perror("mmap() failed for data"); exit(EXIT_FAILURE); } pid_t *pid_counter = mmap(NULL, sizeof *pid_counter, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0); if ( pid_counter == MAP_FAILED ) { perror("mmap() failed for pid_counter"); exit(EXIT_FAILURE); } pid_t pid_reader, temp_pid; sigset_t ss; sigemptyset(&ss); sigaddset(&ss, SIGUSR1); if ( sigprocmask(SIG_BLOCK, &ss, NULL) == -1 ) { perror("sigprocmask() failed"); exit(EXIT_FAILURE); } if ( (pid_reader = fork()) == -1 ) { perror("fork() failed for reader"); exit(EXIT_FAILURE); } else if ( !pid_reader ) { printf("READER: waiting signal from COUNTER\n"); if ( sigwaitinfo(&ss, NULL) == -1 ) { perror("sigwaitinfo() failed in reader"); _exit(EXIT_FAILURE); } printf("READER: got signal\n"); printf("READER: opening file\n"); FILE *f = fopen(argv[1], "r"); if ( !f ) { fprintf(stderr, "Couldn't open input file\n"); _exit(EXIT_FAILURE); } while ( fgets(data, MAX_LEN, f) ) { printf("READER: reading line and waiting signal from COUNTER\n"); if ( kill(*pid_counter, SIGUSR1) == -1 ) { perror("kill() for SIGUSR1 failed in reader"); _exit(EXIT_FAILURE); } if ( sigwaitinfo(&ss, NULL) == -1 ) { perror("sigwaitinfo() failed in reader"); _exit(EXIT_FAILURE); } printf("READER: got signal\n"); } printf("READER: closing file and killing COUNTER\n"); fclose(f); if ( kill(*pid_counter, SIGTERM) == -1 ) { perror("kill() for SIGTERM failed in reader"); _exit(EXIT_FAILURE); } _exit(EXIT_SUCCESS); } if ( (temp_pid = fork()) == -1 ) { perror("fork() failed for counter"); exit(EXIT_FAILURE); } else if ( temp_pid == 0 ) { *pid_counter = getpid(); sleep(1); printf("COUNTER: send signal to READER that COUNTER is ready\n"); while (1) { if ( kill(pid_reader, SIGUSR1) == -1 ) { perror("kill() failed for SIGUSR1 in counter"); _exit(EXIT_FAILURE); } printf("COUNTER: waiting signal from READER\n"); if ( sigwaitinfo(&ss, NULL) == -1 ) { perror("sigwaitinfo() failed in counter"); _exit(EXIT_FAILURE); } printf("COUNTER: got signal\n"); printf("%zu\n", strlen(data)); } _exit(EXIT_SUCCESS); } if ( wait(NULL) == -1 ) { perror("first wait() failed"); exit(EXIT_FAILURE); } if ( wait(NULL) == -1 ) { perror("second wait() failed"); exit(EXIT_FAILURE); } return 0; }
使用以下输出显示的文件:
paul@thoth:~/src$ cat file.txt line one line two line three paul@thoth:~/src$ ./sig file.txt READER: waiting signal from COUNTER COUNTER: send signal to READER that COUNTER is ready COUNTER: waiting signal from READER READER: got signal READER: opening file READER: reading line and waiting signal from COUNTER COUNTER: got signal 9 COUNTER: waiting signal from READER READER: got signal READER: reading line and waiting signal from COUNTER COUNTER: got signal 9 COUNTER: waiting signal from READER READER: got signal READER: reading line and waiting signal from COUNTER COUNTER: got signal 11 COUNTER: waiting signal from READER READER: got signal READER: reading line and waiting signal from COUNTER COUNTER: got signal 1 COUNTER: waiting signal from READER READER: got signal READER: closing file and killing COUNTER paul@thoth:~/src$