免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 5726 | 回复: 11
打印 上一主题 下一主题

进程间共享的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-07-13 09:47 |只看该作者 |倒序浏览
10可用积分
原贴位置:http://linux.chinaunix.net/bbs/thread-903338-1-1.html

由于vfork的设计是为了子进程由于调用exec或exit而提高效率。
环境编程:
v f o r k与f o r k一样都创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用e x e c (或e x i t ),于是也就不会存访该地址空间。不过在子进程调用e x e c或e x i t之前,它在父进程的空间中运行。这种工作方式在某些U N I X的页式虚存实现中提高了效率。
所以vfork的使用是不合理的。

但我做了下面测试:

代码调整:

#include <stdlib.h>
#include <stdio.h>
void err_sys(char* arg, ...)
{
        exit(1);
}
void f1();
void f2();
int main()
{
        f1();
        fprintf(stderr, "%d:after fork\n", getpid());
        f2();
        fprintf(stderr, "%d:main\n", getpid());
        exit(0);
}
void f1()
{
        pid_t pid;
        fprintf(stderr, "%d:f1\n", getpid());
        if((pid=vfork())<-1)
                err_sys("vfork error");
}
void f2()
{
        fprintf(stderr, "%d:f2\n", getpid());
}

一次运行结果:
30308:f1
30309:after fork
30309:f2
30309:main
30308:main

屏蔽红色部分(即"f2();")一次运行结果:
30318:f1
30319:after fork
30319:main
30318:after fork
30318:main

即子进程对f2的调用导致父进程的某些东西被修改了导致父进程在子进程exit后从f2()调用后开始执行,问题就是被修改的这些东西是什么呢?

[ 本帖最后由 apony 于 2007-7-13 10:25 编辑 ]

最佳答案

查看完整内容

系统调用有相当一部分是inline函数,涉及不到出入栈。fprintf和exit不知道在那里找源码,以_exit为例。include/asm-i386/unistd.h#define __NR_exit 1#define __NR__exit __NR_exit#define __syscall_return(type, res) \do { \ if ((unsigned long)(res) >= (unsigned long)(-125)) { \ errno = -(res); \ res = -1; \ } \ return (type) (res); \} while (0)#define _syscall1(type,name,type1,arg1) \type name(typ ...

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
2 [报告]
发表于 2007-07-13 09:47 |只看该作者
系统调用有相当一部分是inline函数,涉及不到出入栈。
fprintf和exit不知道在那里找源码,以_exit为例。




include/asm-i386/unistd.h


#define __NR_exit             1
#define __NR__exit      __NR_exit



#define __syscall_return(type, res) \
do { \
        if ((unsigned long)(res) >= (unsigned long)(-125)) { \
                errno = -(res); \
                res = -1; \
        } \
        return (type) (res); \
} while (0)


#define _syscall1(type,name,type1,arg1) \
type name(type1 arg1) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
        : "=a" (__res) \
        : "0" (__NR_##name),"b" ((long)(arg1))); \
__syscall_return(type,__res); \
}


static inline _syscall1(int,_exit,int,exitcode)



展开如下:

int _exit (int, exitcode)
    {
       long __res

       __asm__volatile ("int $0x80" : "=a"(__res) : "0"(__NP__exit) , "b"((long)(exitcode)));

      do {
          if ((unsigned long)(__res) >= (unsigned long)(-125)) {
                  errno = -(__res);
                  __res = -1;
          }
          return (int) (__res);
      } while (0)
    }

论坛徽章:
0
3 [报告]
发表于 2007-07-13 09:53 |只看该作者
asmlinkage int sys_vfork(struct pt_regs regs)
{
        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
}

do_fork:

...
if (clone_flags & CLONE_VFORK) {
                        p->vfork_done = &vfork;
                        init_completion(&vfork);
                }
...
if (clone_flags & CLONE_VFORK) {
                        wait_for_completion(&vfork);
                        if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) {
                                current->ptrace_message = nr;
                                ptrace_notify ((PTRACE_EVENT_VFORK_DONE << | SIGTRAP);
                        }
                }
...

论坛徽章:
0
4 [报告]
发表于 2007-07-13 10:04 |只看该作者
vfork 保证子进程先执行,直到exec或退出后才会执行父进程.

所以你上面的执行结果很正常.

论坛徽章:
0
5 [报告]
发表于 2007-07-13 10:18 |只看该作者

回复 #3 eagle1597 的帖子

请注意after fork执行次数
原贴标注红色了

论坛徽章:
0
6 [报告]
发表于 2007-07-13 10:45 |只看该作者
确实,我看走了...
是个奇怪的问题.
而且,我还发现:
#include <stdlib.h>
#include <stdio.h>

void f1();

int main()
{
        f1();
        printf("after fork\n");
        return 0;
}
void f1()
{
        pid_t pid;
        printf("f1\n");
        pid=vfork();
}

这个程序执行时会出现  段错误 (core dumped).
而把vfork改为fork则OK.

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
7 [报告]
发表于 2007-07-13 17:21 |只看该作者
说给分就要说话算话!!!!!


clone_vm时,父子进程共享用户栈。以下说明按照屏幕左边是高地址,右边是低地址

子进程丛kernel返回前用户栈:  返回到main中的"after_fork"-->>返回到f1中的if语句之后。

子进程执行完f2之后的用户栈:返回到main中的"main"-->>返回到f2的fprintf语句之后。
但是这里还是一个f2函数中的地址,虽然你的f2函数中后边没语句,但是fprintf本身也是个函数,
“fprintf要返回到的地址”   把原来  “返回到f1中的if语句之后的地址”给冲了




所以父进程执行时用户栈早变成了:返回到main中的"main"-->>返回到f2的fprintf语句之后。

论坛徽章:
0
8 [报告]
发表于 2007-07-13 22:34 |只看该作者
楼上的正解
问题的关键在于父子共享内核堆栈。

论坛徽章:
0
9 [报告]
发表于 2007-07-13 23:42 |只看该作者

论坛徽章:
0
10 [报告]
发表于 2007-07-16 09:50 |只看该作者

回复 #6 塑料袋 的帖子

分数不是问题!!

父进程在子进程结束后为什么是执行fprintf(stderr, "%d:main\n", getpid());而不是exit(0);呢?
或者能有个栈内容变化的图更形象一些。
主要不理解为什么是f2和fprintf都是函数,父进程只是回到f2之后执行。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP