一个诡异的linux c输出问题,望高手不吝赐教。。。
/*程序功能:创建一个子进程,父进程和子进程交替运行。父进程先显示一次“Current time:”, 然后子进程每隔一秒显示一次当前系统日期和时间,共显示三次。以上过程共循环进行五次。*/
pid_t pid,ppid;
/*全局变量*/
void handle(int signo){
int i=0;
time_t now;
if(signo==SIGUSR1){
for(i=0;i<3;i++){
time(&now);
printf("%s",ctime(&now));
sleep(1);
}
}
if(signo==SIGUSR2){
printf("Current time:\n");
kill(pid,SIGUSR1);
}
}
int main(){
int i;
signal(SIGCLD,SIG_IGN);
signal(SIGUSR1,handle);
signal(SIGUSR2,handle);
pid=fork();
if(pid<0){
perror("fork");
exit(-1);
}
else if(pid==0){
ppid=getppid();
for(i=0;i<5;i++){
kill(ppid,SIGUSR2);
pause();
}
exit(0);
}
wait(0);
return 0;
}
程序能通过编译链接,第一次执行的时候能理想输出,如下:
Current time:
Sun Apr 11 09:27:25 2010
Sun Apr 11 09:27:26 2010
Sun Apr 11 09:27:27 2010
Current time:
Sun Apr 11 09:27:28 2010
……
为什么之后再执行时,会出现同一个时间会输出两次情况,如下:
Current time:
Sun Apr 11 09:27:29 2010
Sun Apr 11 09:27:29 2010
Sun Apr 11 09:27:30 2010
Sun Apr 11 09:27:30 2010
Sun Apr 11 09:27:31 2010
Sun Apr 11 09:27:31 2010
Current time:
……
小弟百思不得其解,望各高手不吝赐教
[解决办法]
楼主的进程间同步没做好
注意这句:
for(i=0;i<5;i++){
kill(ppid,SIGUSR2);
子进程向父进程发送消息是连续发的,没有sleep
那么对于两个消息都用同一个消息处理程序,是不是会造成时序上的混乱?
那么这就跟这时候的系统有关系了,调度,消息排队......
楼主先把这个问题解决了,也许就解决你的问题了
[解决办法]
#include <stdio.h>#include <time.h>#include <signal.h>#include <stdlib.h>pid_t pid,ppid;void handle(int signo) { int i=0; time_t now; if (signo==SIGUSR1) { for (i=0;i<3;i++) { time(&now); printf("%s", ctime(&now)); sleep(1); } } if (signo==SIGUSR2) { printf("Current time:\n"); kill(pid, SIGUSR1); }}int main() { int i; int stat; signal(SIGCLD,SIG_IGN); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, handle); pid=fork(); if (pid<0) { perror("fork"); exit(-1); } else if (pid==0) { signal(SIGUSR1, handle); signal(SIGUSR2, SIG_IGN); ppid=getppid(); for (i=0;i<5;i++) { kill(ppid, SIGUSR2); pause(); } exit(0); } wait(&stat); return 0;}
[解决办法]
你改句话就明白了
printf("Current time: %d\n",pid);
[解决办法]
好像是这个样子:
如果pid作全局变量,那么父子进程引用的是同一个地址空间
如果父进程先运行,子进程后运行,子进程在父进程后从fork返回,pid值就为0
pid中的地址就是后调度的进程从fork的返回值
局部变量在栈中分配,用不同的地址空间,就不会有这个问题
if(signo==SIGUSR2){ printf ("pid = %i , addr = %x\n", pid,&pid); printf("Current time:\n"); fflush(0); kill(pid,SIGUSR1); //如果pid为0,那么发信号给当前进程组,所以会输出两次 }
[解决办法]
你代码有两个问题:
1. 进程同步
2. 使用了printf输出,printf输出只是将内容输出到缓冲区中,不能保证能够即时输出。
[解决办法]
问题应该出在写时复制(Copy-On-Write)上,引用一段关于写时复制的描述:
现在的Unix内核(包括Linux),采用一种更为有效的方法称之为写时复制(或COW)。这种思想相当简单:父进程和子进程共享页面而不是复制页面。然而,只要页面被共享,它们就不能被修改。无论父进程和子进程何时试图写一个共享的页面,就产生一个错误,这时内核就把这个页复制到一个新的页面中并标记为可写。原来的页面仍然是写保护的:当其它进程试图写入时,内核检查写进程是否是这个页面的唯一属主;如果是,它把这个页面标记为对这个进程是可写的。
当fork()调用后,父进程和子进程共享地址空间(此时数据段的pid,ppid都为0),其后不管是父进程先返回还是子进程先返回,都要修改pid的值,就会发生缺页错误,内核将复制页面。你的程序的问题就出在这儿,在这个时间段执行kill(pid,SIGUSR1),pid的值就会是0(就是数据段的初始值)。
我在我的ubuntu9.04下测试过,第一次输出时,pid的值是0,后面就会变成子进程的id了。如果将pid初始成其他值,第一次输出pid的值时,也将是那个初始值。过段时间,内核的页复制完成时,pid就会变成子进程ID。
[解决办法]
这是信号处理函数的异步调用引起的,
在进程收到信号后,系统会试图将收到信号
的进程唤醒,而sleep进行阻塞的进程肯定会
被唤醒,而进程被唤醒后立刻执行信号处理函数.
此外,信号处理函数和主程序中是不能同时使用printf的
[解决办法]