判断for()作用域,区分那块属于哪个进程/多进程
2011-11-22 10:50
288 查看
刚开始接触进程(fork())的时候,比较难以理解的是如何实现多进程,也就是不知道如何来fork多个进程。通俗的想法可能是,我fork某个函数,就像我们创建了一个进程,这个函数就在这个进程上跑。这种想法比较贴切我们的观念,但是实际上,fork的机制并不是如此的“智能”,而是需要我们人为地“划定”界限,来规定那一块儿属于哪一个进程。这种描述可能还是不很贴切。
今天看了篇文章,写的不错,让我们能够比较直观地理解fork函数是如何发挥作用的,我呢就不班门弄斧了,这篇博文已经写的相当到位了。
来自:http://hi.baidu.com/aberlee/blog/item/777b99fcf13840f5fd037f0c.html
内容如下:
在一个程序里实现多进程,相对来讲,比在一个程序中实现多线程要更难理解,至少我在开始使用fork()的时候就很容易犯糊涂,所以一步一步来记录学习的过程。先来一段最简单的:
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
fork();
printf("after fork(), pid = %d\n", getpid());
return 0;
}
fork()的调用,就意味着从fork()的位置开始分叉,从一个进程变成了两个进程,原进程成为父进程,叉出来的进程成为子进程。分叉之前的程序代码是由父进程执行的,但执行后的数据一式两份,俩人都可以分别继续使用。分叉之后的程序代码,两个进程就会分别执行一遍。那么上面这个程序的运行输出会是:
before fork(), pid = 3425
after fork(), pid = 3425
after fork(), pid = 3426
可以看到 printf("after fork(), pid = %d\n", getpid());
被调用了两次(实际上 return 0; 也是被调用了两次)。一次是父进程干的,一次是子进程干的。输出不同是因为两个进程的pid是不同的。需要留意的是,这两次调用的顺序是不可控的,有时候是父前子后,有时候是子前父后。
使用多进程,为的是执行多个不同的任务。如果每次父进程和子进程都运行的是一样的代码,那就没啥实际的意义了。如何实现分叉后两个进程各自执行各自的代码呢?很简单,根据fork()的返回值来判断。fork()一次调用,却返回两个值:向父进程返回子进程的pid号,向子进程返回0。也有可能只返回一个值-1,创建失败的情况,-1当然是向父进程返回的,因为子进程都没有被创建。那么在两个进程中,就是通过fork()的返回值来区分我到底在哪个进程中的。看这一段代码:
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p = fork();
if( p == 0 )
{
printf("in child, pid = %d\n", getpid());
}
else
{
printf("in parent, child pid = %d\n", p);
printf("in parent, pid = %d\n", getpid());
}
return 0;
}
这段程序的运行结果会是:
before fork(), pid = 3425
in child, pid = 3426
in parent, child pid = 3426
in parent, pid = 3425
后面三句输出的顺序同样是不可控的,也完全有可能是这样子:
before fork(), pid = 3425
in parent, child pid = 3426
in child, pid = 3426
in parent, pid = 3425
实际上fork()分叉之后,父进程和子进程运行的仍然是同一代码段,只不过可以根据fork()的返回值用if语句来控制,
父进程运行这部分:
printf("in parent, child pid = %d\n", p);
printf("in parent, pid = %d\n", getpid());
子进程运行那部分:
printf("in child, pid = %d\n", getpid());
二者都会运行到程序结尾的 return 0;然后结束。这个程序还有另一种写法,更容易理解一点,让子进程终结在
if(pid=0){...} 里。
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p = fork();
if( p == 0 )
{
printf("in child, pid = %d\n", getpid());
return 0;
}
printf("in parent, child pid = %d\n", p);
printf("in parent, pid = %d\n", getpid());
return 0;
}
这段程序和上面那个运行结果是一样的。不可控的运行顺序很烦人,正常情况下会需要等待子进程执行完毕之后再来结束父进程,可以用waitpid()来等待子进程的结束。
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p = fork();
if( p == 0 )
{
printf("in child, pid = %d\n", getpid());
return 0;
}
int st;
waitpid( p, &st, 0);
printf("in parent, child pid = %d\n", p);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child exited with %d\n", st);
return 0;
}
这段程序的输出顺序就会确定的:
before fork(), pid = 3425
in child, pid = 3426
in parent, child pid = 3426
in parent, pid = 3425
in parent, child exited with 0
创建两个子进程应该怎么搞呢,这样子试试看:
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p1 = fork();
pid_t p2 = fork();
if( p1 == 0 )
{
printf("in child 1, pid = %d\n", getpid());
return 0;
}
if( p2 == 0 )
{
printf("in child 2, pid = %d\n", getpid());
return 0;
}
int st1, st2;
waitpid( p1, &st1, 0);
waitpid( p2, &st2, 0);
printf("in parent, child 1 pid = %d\n", p1);
printf("in parent, child 2 pid = %d\n", p2);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child 1 exited with %d\n", st1);
printf("in parent, child 2 exited with %d\n", st2);
return 0;
}
程序的输出会是:
before fork(), pid = 8624
in child 1, pid = 8626
in child 1, pid = 8625
in child 2, pid = 8627
in parent, child 1 pid = 8625
in parent, child 2 pid = 8627
in parent, pid = 8624
in parent, child 1 exited with 0
in parent, child 2 exited with
可以看到 in child1... 出现了两次,两次的pid却不相同。说明这段程序是有问题的,想要创建两个子进程,却出现了三个子进程。这句话 printf("in child 1, pid = %d\n", getpid());被执行了两次,这是预料之外的。为什么会这样呢?可以分别来看一下父进程、子进程1号、子进程2号,fork()之后分别应该执行的代码段。
父进程:
int st1, st2;
waitpid( p1, &st1, 0);
waitpid( p2, &st2, 0);
printf("in parent, child 1 pid = %d\n", p1);
printf("in parent, child 2 pid = %d\n", p2);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child 1 exited with %d\n", st1);
printf("in parent, child 2 exited with %d\n", st2);
return 0;
子进程1号:
pid_t p2 = fork();
if( p1 == 0 )
{
printf("in child 1, pid = %d\n", getpid());
return 0;
}
子进程2号:
if( p2 == 0 )
{
printf("in child 2, pid = %d\n", getpid());
return 0;
}
可以很明显的看到子进程1号里还有个fork(),也就是说子进程1号又创建了一个子进程,才导致printf("in child 1, pid = %d\n", getpid());被执行了两次。我们可以在子进程1号的代码段中捕捉这个子进程的子进程。
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p1 = fork();
pid_t p2 = fork();
if( p1 == 0 )
{
if( p2 == 0 )
{
printf("int child 1's child, pid = %d, ppid = %d\n", getpid(), getppid());
return 0;
}
printf("in child 1, pid = %d\n", getpid());
return 0;
}
if( p2 == 0 )
{
printf("in child 2, pid = %d\n", getpid());
return 0;
}
int st1, st2;
waitpid( p1, &st1, 0);
waitpid( p2, &st2, 0);
printf("in parent, child 1 pid = %d\n", p1);
printf("in parent, child 2 pid = %d\n", p2);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child 1 exited with %d\n", st1);
printf("in parent, child 2 exited with %d\n", st2);
return 0;
}
程序的输出如下:
before fork(), pid = 8664
int child 1's child, pid = 8666, ppid = 8665
in child 1, pid = 8665
in child 2, pid = 8667
in parent, child 1 pid = 8665
in parent, child 2 pid = 8667
in parent, pid = 8664
in parent, child 1 exited with 0
in parent, child 2 exited with 0
可以看到“子进程1号的子进程”的ppid就等于子进程1号的pid。为什么要花这么多字来分析这种错误的写法,是因为我曾经被这个错误搞得很糊涂。创建和使用两个甚至更多个子进程的正确方法如下:
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p1 = fork();
if( p1 == 0 )
{
printf("in child 1, pid = %d\n", getpid());
return 0;
}
pid_t p2 = fork();
if( p2 == 0 )
{
printf("in child 2, pid = %d\n", getpid());
return 0;
}
int st1, st2;
waitpid( p1, &st1, 0);
waitpid( p2, &st2, 0);
printf("in parent, child 1 pid = %d\n", p1);
printf("in parent, child 2 pid = %d\n", p2);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child 1 exited with %d\n", st1);
printf("in parent, child 2 exited with %d\n", st2);
return 0;
}
让创建子进程的fork()紧跟着子进程要运行的代码段,子进程之间就不会再互相影响。为了方便的实现多进程,还可以把创建子进程的部分单独列为一个函数,这样更容易理解(像线程一样)。请看我的终极多任务程序框架:
pid_t create_child()
{
pid_t p = fork();
if( p == 0 )
{
printf("in child %d\n", getpid());
//do something
return 0;
}
return p;
}
int main(void)
{
pid_t p1 = create_child();
pid_t p2 = create_child();
int st1, st2;
waitpid( p1, &st1, 0);
waitpid( p2, &st2, 0);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child 1 exited with %d\n", st1);
printf("in parent, child 2 exited with %d\n", st2);
return 0;
}
今天看了篇文章,写的不错,让我们能够比较直观地理解fork函数是如何发挥作用的,我呢就不班门弄斧了,这篇博文已经写的相当到位了。
来自:http://hi.baidu.com/aberlee/blog/item/777b99fcf13840f5fd037f0c.html
内容如下:
在一个程序里实现多进程,相对来讲,比在一个程序中实现多线程要更难理解,至少我在开始使用fork()的时候就很容易犯糊涂,所以一步一步来记录学习的过程。先来一段最简单的:
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
fork();
printf("after fork(), pid = %d\n", getpid());
return 0;
}
fork()的调用,就意味着从fork()的位置开始分叉,从一个进程变成了两个进程,原进程成为父进程,叉出来的进程成为子进程。分叉之前的程序代码是由父进程执行的,但执行后的数据一式两份,俩人都可以分别继续使用。分叉之后的程序代码,两个进程就会分别执行一遍。那么上面这个程序的运行输出会是:
before fork(), pid = 3425
after fork(), pid = 3425
after fork(), pid = 3426
可以看到 printf("after fork(), pid = %d\n", getpid());
被调用了两次(实际上 return 0; 也是被调用了两次)。一次是父进程干的,一次是子进程干的。输出不同是因为两个进程的pid是不同的。需要留意的是,这两次调用的顺序是不可控的,有时候是父前子后,有时候是子前父后。
使用多进程,为的是执行多个不同的任务。如果每次父进程和子进程都运行的是一样的代码,那就没啥实际的意义了。如何实现分叉后两个进程各自执行各自的代码呢?很简单,根据fork()的返回值来判断。fork()一次调用,却返回两个值:向父进程返回子进程的pid号,向子进程返回0。也有可能只返回一个值-1,创建失败的情况,-1当然是向父进程返回的,因为子进程都没有被创建。那么在两个进程中,就是通过fork()的返回值来区分我到底在哪个进程中的。看这一段代码:
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p = fork();
if( p == 0 )
{
printf("in child, pid = %d\n", getpid());
}
else
{
printf("in parent, child pid = %d\n", p);
printf("in parent, pid = %d\n", getpid());
}
return 0;
}
这段程序的运行结果会是:
before fork(), pid = 3425
in child, pid = 3426
in parent, child pid = 3426
in parent, pid = 3425
后面三句输出的顺序同样是不可控的,也完全有可能是这样子:
before fork(), pid = 3425
in parent, child pid = 3426
in child, pid = 3426
in parent, pid = 3425
实际上fork()分叉之后,父进程和子进程运行的仍然是同一代码段,只不过可以根据fork()的返回值用if语句来控制,
父进程运行这部分:
printf("in parent, child pid = %d\n", p);
printf("in parent, pid = %d\n", getpid());
子进程运行那部分:
printf("in child, pid = %d\n", getpid());
二者都会运行到程序结尾的 return 0;然后结束。这个程序还有另一种写法,更容易理解一点,让子进程终结在
if(pid=0){...} 里。
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p = fork();
if( p == 0 )
{
printf("in child, pid = %d\n", getpid());
return 0;
}
printf("in parent, child pid = %d\n", p);
printf("in parent, pid = %d\n", getpid());
return 0;
}
这段程序和上面那个运行结果是一样的。不可控的运行顺序很烦人,正常情况下会需要等待子进程执行完毕之后再来结束父进程,可以用waitpid()来等待子进程的结束。
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p = fork();
if( p == 0 )
{
printf("in child, pid = %d\n", getpid());
return 0;
}
int st;
waitpid( p, &st, 0);
printf("in parent, child pid = %d\n", p);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child exited with %d\n", st);
return 0;
}
这段程序的输出顺序就会确定的:
before fork(), pid = 3425
in child, pid = 3426
in parent, child pid = 3426
in parent, pid = 3425
in parent, child exited with 0
创建两个子进程应该怎么搞呢,这样子试试看:
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p1 = fork();
pid_t p2 = fork();
if( p1 == 0 )
{
printf("in child 1, pid = %d\n", getpid());
return 0;
}
if( p2 == 0 )
{
printf("in child 2, pid = %d\n", getpid());
return 0;
}
int st1, st2;
waitpid( p1, &st1, 0);
waitpid( p2, &st2, 0);
printf("in parent, child 1 pid = %d\n", p1);
printf("in parent, child 2 pid = %d\n", p2);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child 1 exited with %d\n", st1);
printf("in parent, child 2 exited with %d\n", st2);
return 0;
}
程序的输出会是:
before fork(), pid = 8624
in child 1, pid = 8626
in child 1, pid = 8625
in child 2, pid = 8627
in parent, child 1 pid = 8625
in parent, child 2 pid = 8627
in parent, pid = 8624
in parent, child 1 exited with 0
in parent, child 2 exited with
可以看到 in child1... 出现了两次,两次的pid却不相同。说明这段程序是有问题的,想要创建两个子进程,却出现了三个子进程。这句话 printf("in child 1, pid = %d\n", getpid());被执行了两次,这是预料之外的。为什么会这样呢?可以分别来看一下父进程、子进程1号、子进程2号,fork()之后分别应该执行的代码段。
父进程:
int st1, st2;
waitpid( p1, &st1, 0);
waitpid( p2, &st2, 0);
printf("in parent, child 1 pid = %d\n", p1);
printf("in parent, child 2 pid = %d\n", p2);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child 1 exited with %d\n", st1);
printf("in parent, child 2 exited with %d\n", st2);
return 0;
子进程1号:
pid_t p2 = fork();
if( p1 == 0 )
{
printf("in child 1, pid = %d\n", getpid());
return 0;
}
子进程2号:
if( p2 == 0 )
{
printf("in child 2, pid = %d\n", getpid());
return 0;
}
可以很明显的看到子进程1号里还有个fork(),也就是说子进程1号又创建了一个子进程,才导致printf("in child 1, pid = %d\n", getpid());被执行了两次。我们可以在子进程1号的代码段中捕捉这个子进程的子进程。
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p1 = fork();
pid_t p2 = fork();
if( p1 == 0 )
{
if( p2 == 0 )
{
printf("int child 1's child, pid = %d, ppid = %d\n", getpid(), getppid());
return 0;
}
printf("in child 1, pid = %d\n", getpid());
return 0;
}
if( p2 == 0 )
{
printf("in child 2, pid = %d\n", getpid());
return 0;
}
int st1, st2;
waitpid( p1, &st1, 0);
waitpid( p2, &st2, 0);
printf("in parent, child 1 pid = %d\n", p1);
printf("in parent, child 2 pid = %d\n", p2);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child 1 exited with %d\n", st1);
printf("in parent, child 2 exited with %d\n", st2);
return 0;
}
程序的输出如下:
before fork(), pid = 8664
int child 1's child, pid = 8666, ppid = 8665
in child 1, pid = 8665
in child 2, pid = 8667
in parent, child 1 pid = 8665
in parent, child 2 pid = 8667
in parent, pid = 8664
in parent, child 1 exited with 0
in parent, child 2 exited with 0
可以看到“子进程1号的子进程”的ppid就等于子进程1号的pid。为什么要花这么多字来分析这种错误的写法,是因为我曾经被这个错误搞得很糊涂。创建和使用两个甚至更多个子进程的正确方法如下:
int main(void)
{
printf("before fork(), pid = %d\n", getpid());
pid_t p1 = fork();
if( p1 == 0 )
{
printf("in child 1, pid = %d\n", getpid());
return 0;
}
pid_t p2 = fork();
if( p2 == 0 )
{
printf("in child 2, pid = %d\n", getpid());
return 0;
}
int st1, st2;
waitpid( p1, &st1, 0);
waitpid( p2, &st2, 0);
printf("in parent, child 1 pid = %d\n", p1);
printf("in parent, child 2 pid = %d\n", p2);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child 1 exited with %d\n", st1);
printf("in parent, child 2 exited with %d\n", st2);
return 0;
}
让创建子进程的fork()紧跟着子进程要运行的代码段,子进程之间就不会再互相影响。为了方便的实现多进程,还可以把创建子进程的部分单独列为一个函数,这样更容易理解(像线程一样)。请看我的终极多任务程序框架:
pid_t create_child()
{
pid_t p = fork();
if( p == 0 )
{
printf("in child %d\n", getpid());
//do something
return 0;
}
return p;
}
int main(void)
{
pid_t p1 = create_child();
pid_t p2 = create_child();
int st1, st2;
waitpid( p1, &st1, 0);
waitpid( p2, &st2, 0);
printf("in parent, pid = %d\n", getpid());
printf("in parent, child 1 exited with %d\n", st1);
printf("in parent, child 2 exited with %d\n", st2);
return 0;
}
相关文章推荐
- Android根据输入银行卡号判断属于哪个银行
- 根据IP地址判断客户端属于哪个国家或地区
- 判断Windows中移动存储被哪个进程占用的办法
- 正则表达式判断手机号码属于哪个运营商
- 判断手机号码属于哪个地区 哪个运营商(移动、联通、电信、)
- 判断是否是64位系统(之前那个是判断是否是64位进程不一样。注意区分)
- Android 判断SIM卡属于哪个移动运营商
- 判断SIM卡属于哪个移动运营商
- 安卓ExpandableListView长按监听判断点击的item属于哪个group(群组)和child(子项)
- Android 判断SIM卡属于哪个移动运营商
- Android 判断SIM卡属于哪个移动运营商的实现代码
- Android判断SIM卡属于哪个移动运营商
- 判断SIM卡属于哪个移动运营商
- 判断SIM卡属于哪个移动运营商
- Android 多进程环境判断当前进程是否是UI进程
- Java 基础源码 switch语句判断指定月份属于一年中的哪个季度
- Java 基础源码 switch语句判断指定月份属于一年中的哪个季度
- Android 判断SIM卡属于哪个移动运营商详解及实例
- Android 判断SIM卡属于哪个移动运营商
- 判断SIM卡属于哪个移动运营商