一直以来,我都认为在Linux下使用fork创建的新的进程和父进程具有相同的代码段和相同的全局数据段,但是今天遇到了一点问题!!!!
例程:使用父子进程共同打印一段字符串,子进程打印前半,父进程后半,时间间隔1s,初步源码如下:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int i,j;
pid_t pid;
const char *message="this is a test string\n";
int n = strlen(message) / 2;
pid = fork();
j = (pid == 0 ? 0 : n);
for ( i = 0; i < n; i++)
{
write(STDOUT_FILENO,message + i + j,1);
sleep(1);
}
return 0;
}
//运行结果混乱。
因为涉及到同步的的问题,所以使用信号量来解决,代码如下:
#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> int main() { int i,j; pid_t pid; const char *message="this is a test string\n"; int n = strlen(message) / 2;
sem_init(&sem,2,0);pid = fork();sem_t sem;
j = (pid == 0 ? 0 : n);
if(pid > 0)
{
sem_wait(&sem);
}
for ( i = 0; i < n; i++)
{
write(STDOUT_FILENO,message + i + j,1);
sleep(1);
}
if(pid == 0)
{
sem_post(&sem);
}
sem_destroy(&sem);
return 0;
}
//结果子进程正常打印,父进程一直等待获取信号量的位置。
十分不解,使用gdb调试后发现,在子进程中出现的效果和自己设想的一样(即:sem.__align的值+1),按理说这样后父进程能够获取到信号量才对。。。很明显了,父子进程的地址空间的虚拟地址一样,但是指向的数据区域的实际物理地址不一样。。。。
然后稍微的改了一下程序,将sem_t sem;定义为全局变量,但是结果依旧。。子进程仍然无法改变父进程的地址空间中的值。
然后就将无名信号改成了有名信号:程序如下:
然后。。。。突然醒悟。。。。#include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> //static sem_t sem; int main() { int i,j; pid_t pid; const char *message="this is a test string\n"; int n = strlen(message) / 2; sem_t *sem; sem = sem_open("/sem", O_CREAT, S_IRUSR | S_IWUSR, 0); pid = fork(); j = (pid == 0 ? 0 : n); if(pid > 0) { sem_wait(sem); } for ( i = 0; i < n; i++) { write(STDOUT_FILENO,message + i + j,1); sleep(1); } if(pid == 0) { sem_post(sem); } sem_destroy(sem); return 0; } //得到了预期结果
如果父子进程能够直接共享局部变量和全局变量数据,还用管道、共享内存……干嘛。。。。