linux下的多进程编程

1多进程编程
  1.1进程和程序的区别
  1.2查看一下进程
     1)简单形式:ps命令 默认打开终端
2)ps的参数:
   ps -aux 查看计算机中所有的进程(linux专用)
      -a:所有用户有控制终端的进程
  -u:以相近方式列出
  -x:显示无控制终端的进程(守护进程)
ps -elf (linux/unix)
  -e:显示所有用户的进程
  -l:按照常格式显示
  -f:完整格式显示
  1.3为什么要引入多进程?
随着CPU运算能力的提高,为了提高CPU的使用效率,引入了多进程机制,使得终端用户可以在一台机械同时并行做N件事。宏观上并行,微观上串行。
  1.4关于父进程和子进程
        操作系统中的多进程是有启动次序的。UNIX先启动的进程是0号进程。0号进程启动1号进程,再由1号进程,其它进程再启动其它进程。
如果进程A启动了进程B,那么A叫做B的父进程,B叫做A的子进程。
        进程用进程号PID来表示。
        进程用进程PID来表示,PID是一个非负整数,PID可以延时重用。同一时刻保持唯一性
如果获取一个进程的PID:
        getpid():获取进程的PID
getppid():获取父进程的PID
  1.5 创建一个子进程的方法
        1)fork()创建子进程
2)vfork()| execl() 创建子进程

1.5.1 fork()

   fork()是一个非常简单又复杂的函数
    pid_t fork(void);
    返回子进程的PID,或者0
     失败返回-1

     fork()通过复制父进程的内存空间,创建子进程,复制除了代码区域之外的所有区域,共享代码区域父子进程共享。

     1)fork()会创建子进程,子进程从fork()当前位置开始执行代码,fork()之前的代码父进程执行一次,fork()之后的代码父子进程个执行一次。

      2)fork()会返回两次,父进程返回子进程的PID,子进程返回0

2 多进程编程
为什么引进多进程?
ps -elf
ps -aux
系统首先启动0号进程,然后由0号启动1号,然后由1号进程启动其它进程,其它进程再启动其它进程
父子进程的概念
每个进程都有一个PID,PID是一个非负整数

3 如何让创建子进程
1)fork()
2)vfork()+ excel()
3.1 fork 
pid_t fork(void)
复制父进程的内存空间,创建子进程,复制除了代码区域之外的所有区域,共享代码区域父子进程共享。
fork()返回两次,在父进程中执行fork()的return返回子进程的PID,在子进程中执行的fork返回0。
fork() 之前的代码只有父进程执行,fork()之后的代码父子进程都有机会执行,受代码逻辑的控制而进入不同的分支。
问题1:forktest.c对应的a.out执行会开启多少个进程?
fork()创建子进程时会复制代码区之外的所有区域,包括缓冲区。子进程中创建的变量父进程不能使用。
fork()之后先执行子进程还是父进程,不确定。
fork()创建子进程时,如果父进程存在文件描述符,则子进程复杂文件描述符,不复制文件表,共用同一个文件表(offset)。
如果父进程先于子进程结束,子进程编程孤儿进程,该孤儿进程被1号进程1号进程收养。
如果子进程结束时,会给父进程发信号,如果父进程没有及时处理,子进程将变成僵尸(zombie)进程,直达父进程处理了该信号或父进程退出。


4.如何退出进程?
    int main()

...
return 0;
return -1;
//交给他的父进程

4.1 进程的退出方式
1)正常退出
a.在main函数中执行return语句
b.exit函数退出进程
c._exit和_Exit函数
d.最后一个线程退出
f.主线程退出
2)非正常退出
a.被信号打断导致退出,例如:ctrl+c
b.进程中的最后一个线程被取消
4.2 exit()、 _exit()和_Exit()
1)_exit()和_Exit()作用是一样的,区别在于头文件不同,一个是UC函数,一个标c的函数
_exit():#include <unistd.h>
       _Exit():#include <stdlib.h>
2)_exit()和_Exit()立即使进程退出
3)exit不是立即退出,可以调试执行一些其他函数后再退出。
  可以使用atexit()函数注册一系列函数,然后这个函数在exit退出进程之前被调自动调用。
  当执行exit函数或者在主函数里面执行return函数时,都会调用这些函数。
  exit(n)中的n值不能超过255,超过也无意义。
4.3 取得子进程的退出状态和退出码
wait()函数和waitpid()函数可以让父进程等到子进程结束,并取得子进程的退出状态和退出
码(return语句后面的值或者exit(n))。
4.3.1 wait()
等待任意一个子进程结束后就返回。
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
status是一个传出参数,用来带回结束子进程的退出状态和退出码
返回值是结束的子进程的PID,否则等待该父进程对应的子进程结束(阻塞等待)
        出错返回-1,errno ECHILD
宏:WIFEXIT(status)
宏:WIFWXITED(status) 判断进程是否正常结束(exit return _exit _Exit)
   WEXITSTATUS(status)
等待子进程结束
4.3.2 waitpid()
用来选择等待某个特定的子进程结束,再返回
pid_t waitpid(pid_t pid, int *status, int options);

5 vfork + exec
#include <sys/types.h>
#include <unistd.h>
vfork和fork在语法上没有任何区别,唯一的区别在于vfork不复制父进程的任何资源,而是直接占用父进程的资源运行代码,父进程处于阻塞状态,直到子进程结束或者调用了exec系列函数
excl是一系列的函数,6个函数,使用全新的的程序替换当前进程中的代码段,数据段、堆区、栈区、保留原进程的PID:
execl/execlp/execle
execv/execvp/execve
前四个字符统一为:exec
第五个字符的取值为:l list:参数传递为逐个例举的方式
v vector:参数传递为构造指针数组的方式
第六个字符的取值为:e environ:可以给新进程传递环境变量表
p path:可以传递路径
execl:第一参数执行文件的路径+名称
      第二参数为通常执行文件的名称
       后续参数,该文件执行需要的具体参数,最后一个参数必须为NULL
execl("/bin/ls", "ls", "-l", "/home/administrator", NULL);
execlp:第一个参数执行文件的名称,不用加路径,会自动从path指定的路径中寻找要执行的程序。  
后续参数与execl相同
 execlp("ls", "-l", "/home/administrator", NULL);
execvp:最后一个参数必须为NULL
char arg[]={"/bin/ls", "ls", "-l", "/home/administrator", NULL}
execvp("ls", arg);
execv:
        char arg[]={"ls", "-l", "/home/administrator", NULL}
execvp("ls", arg);
vfork + exec 的使用: 
用途:1)可以直接编程调用系统中提供的可执行命令
    2)降低了模块之间的耦合度
缺点:以上用法去调用系统命令时会有一些列的问题,例如通配符,重定向问题

execl("bash", "bash", "-c", "ls *.c>a.txt", NULL);
system(...):
用shell来调用程序 = fork + exec + waitpid
该函数的参考实现《unix高级编程》p167
system("ls *.c>a.txt")

system  和  vfork + exec 哪个效率更高?
vfork + exec 的效率更高。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值