进程

什么是进程:

   简单的说,进程就是正在执行的程序。执行程序的时候,内核会为程序分配空间,记录有进程相关的各种信息,并且为进程分配各种计算机资源,在进程结束后,内核会回收资源,供其他进程使用。



进程的内存布局:

    文本:程序的指令

    数据:程序使用的静态变量

    堆:程序可以从这个区域动态分配内存

    栈:用于为局部变量和函数调用链接信息分配储存空间,随着函数的调用、返回而增减的内存




创建进程:

   用fork函数可以创建新的进程,新进程叫做子进程,原进程叫做父进程,子进程是父进程的copy,包括数据空间,堆和栈的副本,所以父进程和子进程的内存空间不同(但是在内存中标记为只读的内存可以在父子进程之间共享,如果父子进程中任意一个进程试图修改该内存,将会为修改的内存单独创建副本,这个技术叫做写时复制技术Copy-On-Write)

   fork函数被调用一次会返回两次,子进程的返回值是0,而父进程的返回值则是子进程的进程编号PID(Procress Identification),每个进程都有一个唯一的PID来标识,此外还有一个父进程来(PPID),用来标识请求内核创建自己的进程。

#include <stdio.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <errno.h>

 int global_a = 10;

 int main()
 {
         printf("pid = %d,ppid = %d\n",getpid(),getppid());
         int local_b = 100;
         int *heap_c = (int *)malloc(sizeof(int));
         *heap_c = 1000;

         pid_t pid = fork();
         if(pid == -1)
         {
                 perror("fork failed.");
                 _exit(errno);
         }
         if(0 == pid){
                 printf("this is a child progrocess,pid = %d, ppid = %d\n",getpid(),getppid());
                 ++global_a,--local_b;
                 *heap_c += 1;
                 printf("[child]a= %d,b = %d,c = %d\n",global_a,local_b,*heap_c);
                _exit(0);

                 }
         else {
                sleep(1);
                 printf("this is parent,pid = %d,child pid = %d\n",getpid(),pid);
                 printf("[parent]a = %d,b = %d,c = %d\n ",global_a,local_b,*heap_c);
                _exit(errno);
         }
         return 0;

 }

输出:
pid = 5038,ppid = 3198
this is a child progrocess,pid = 5039, ppid = 5038
[child]a= 11,b = 99,c = 1001
this is parent,pid = 5038,child pid = 5039
[parent]a = 10,b = 100,c = 1000

父子进程的global_a,local_b,heap_c的取值都不相同,所以他们财产分家了大笑
将sleep(1)注释掉后,发现输出是这样:

pid = 5056,ppid = 3198
this is parent,pid = 5056,child pid = 5057
[parent]a = 10,b = 100,c = 1000
this is a child progrocess,pid = 5057, ppid = 5056
[child]a= 11,b = 99,c = 1001

可见父进程先下手返回了pid(姜还是老的辣偷笑


   我们创建进程肯定不是为了去执行父进程那些老套的代码,子进程有自己的想法,于是需要用到exec函数去加载新的程序替换掉老的代码、数据、堆栈。exec总共有6个函数,统称exec.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

extern char **environ;

void exec_demo()
{
        printf("---%s---\n",__FUNCTION__);
        /*execl,可变参数列表以NULL结束*/
        execl("/bin/ls","/bin/ls","-l","-a",NULL);
        printf("execl failed !\n");

}
int main()
{
        exec_demo();
        printf("My child dont't want me anymore! wuwu...\n ");
        return 0;
}
execl()函数的第一个参数是将要执行的新的程序名,可以是加路径,之后的参数是对这个命令的描叙参数,通常第一个是程序名,接下来的是这个命令的可选参数

execl的l就是代表这个参数列表

打印出:

---exec_demo---
总用量 64
drwxrwxr-x 3 jack jack  4096  1月 25 23:21 .
drwxr-xr-x 6 jack jack  4096  1月 25 20:39 ..
-rwxrwxr-x 1 jack jack  8689  1月 25 23:21 1
-rw-rw-r-- 1 jack jack   354  1月 25 23:20 exec.c
-rw------- 1 jack jack 12288  1月 25 23:20 .exec.c.swp
-rw------- 1 jack jack 12288  1月 25 20:07 .fopen.c.swp
-rw-r--r-- 1 jack jack 12288  1月 23 20:51 .main.c.swp
drwxrwxr-x 3 jack jack  4096  1月 23 14:12 .metadata
相当于执行命令ls -l  -a,并且看不到printf函数的输出内容,这是因为执行execl函数用新的代码覆盖了旧的代码




当然,exec函数一般都是配合fork函数使用的,先fork一个新进程,再exec去执行新的程序

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 #include <unistd.h>
  5 #include <sys/types.h>
  6 #include <sys/wait.h>
  7
  8 int main()
  9 {
 10         printf("---fork+exec---\n");
 11         pid_t pid = fork();
 12         if(pid == -1)
 13         {
 14                 perror("fork");
 15                 _exit(-1);
 16         }
 17         if(0 == pid){
 18                 printf("child :pid = %d,ppid = %d\n",getpid(),getppid());
 19                 execlp("sh","sh","-c","firefox http://baidu.com",NULL);
 20                 fprintf(stderr,"execlp failed");
 21                 _exit(-1);
 22         }
 23         printf("parent,pid = %d,child pid = %d\n",getpid(),pid);
 24         return 0;
 25
 26 }

这里execlo的p代表PATH,表明新的执行程序要到环境变量中一个个去寻找

同样printf的内容不会输出,而是会用firefox打开一个百度网页哦!








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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值