LINUX复习_2_进程

概念及定义
1:linux下,进程在内存中有三部分的数据:代码段,数据段,堆栈段
代码段:存放程序代码的数据
堆栈段:存放子程序的返回地址,参数及程序的局部变量
数据段:存放程序的全局变量,常数以及动态数据分配的数据空间。

2:进程向量数组task ,task数组是操作系统管理线程的基础
task_truct结构庞大且复杂,了解一下就行。

pstree -p//命令查看进程树

3:进程分为2大类:系统进程,用户进程

4:进程控制——fork() / exec() / wait() / exit()

用户使用系统调用fork()来创建一个进程,而系统调用fork()需要完成下列几步:
 第一步,为新进程在进程表中分配一个表项。系统对一个用户可以同时运行的进程数是有限制的,对超级用户没有该限制,但也不能超过进程表的最大表项的数目。

 第二步,给子进程一个唯一的进程标识号(PID)。该进程标识号其实就是该表项在进程表中的索引号。

 第三步,复制一个父进程的进程表项的副本给子进程。内核初始化子进程的进程表项时,是从父进程处拷贝的。所以子进程拥有与父进程一样的 uid、 euid、 gid、用于计算优先权的 nice 值、当前目录、当前根、用户文件描述符表等。

 第四步,把与父进程相连的文件表和索引节点表的引用数加 l。这些文件自动地与该子进程相连。

 第五步,内核为子进程创建用户级上下文。内核为子进程的 u 区及辅助页表分配内存,并复制父进程的区内容。这样生成的是进程的静态部分。
  
 第六步,生成进程的动态部分,内核复制父进程的上下文的第一层,即寄存器上下文和内核栈,内核再为子进程虚设一个上下文层,这是为了子进程能“ 恢复” 它的上下文。这时,该调用会对父进程返回子进程的 pid,对子进程返回 0。

wait():
  一个进程通过用 wait()来与它的子进程同步,如果发出 wait()调用的进程没有子进程则返回一个错误,如果找到一个僵尸的子进程就取子进程的 PID 及子进程退出时的退出参数。如果有子进程,但没有僵尸的子进程,发出 wait()调用的进程就将进入可中断的睡眠状态,直到收到一个子进程僵尸(SIGCLD)的信号或其他信号

exit():
  Linux 系统的系统调用 exit()是进程用来终止执行的。进程发出该调用,内核就会释放该进程所占的资源,释放进程上下文所占的内存空间,但进程表项还被保留,内核将进程表项中纪录进程状态的字段设为僵尸状态。内核在进程收到不可捕捉的信号时,会从内核内部调用 exit(),使得进程退出。父进程通过 wait()得到其子进程的进程表项中记录的计时数据,并释放进程表项。最后,内核使得进程 1( init 进程)接收终止执行的进程的所有子进程。如果有子进程僵尸,就向 init 进程发出一个 SIGCHLD 的中断信号

exec():
  进程控制的另一个主要内容就是对其他程序引用。该功能是通过系统调用exec()来实现的, exec()调用将一个可执行的程序文件读入并执行。内核读入程序文件正文,清除原先进程的数据区,清除原先进程的中断信号处理函数的地址,当 exec()调用返回时, 进程执行新的正文。

5:调度策略
系统中可以分为2种进程:一般进程,实时进程(权限高)
实时进程也有2种策略:轮流策略,先进先出策略

6:线程
进程是资源管理的最小单位,线程是程序的最小单位

线程和进程的关系是:线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一物理内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。一个进程至少需要一个线程作为它的指令执行体,进程管理着资源(比如 cpu、内存、 文件等等),而将线程分配到某个 cpu 上执行。

不同的进程之间享有独立的空间,只能通过进程间的通信来进行数据的传递,费时费力!!同一进程下的线程共享数据空间,方便快捷,但有很多地方需要注意!!

进程编程

7:ID标识:
用户标识号(UID):用于标识正在运行进程的用户。
用户组标识号(GID):用于标识运行进程的用户所属的组ID。
进程标识号(PID):用于标识进程。
进程组标识号(process group ID):用于进程所属的进程组ID。一个进程可以属于某个进程组。可以发送信号给一组进程。 注意,它不同于GID

需要用到的头文件:

#include<sys/types.h
#include<unistd.h>

getuid()系统调用,获得进程的用户标识号。
getgid()系统调用,捩得进程的用户所属的用户组 ID。
getpid()系统调用,要获得当前进程的 ID。
getppid()系统调用,狭得当前进程的父进程的 ID。
getpgrp()系统调用,获得当前进程所在的进程组的 ID。
getpgid(pid_t)系统调用,获得进程 ID 为 pid 的进程所在的进程组 ID

fork()生成的派生进程与父进程之间没有先后关系,所以在执行fork之后,执行顺序是未知的,但是一般情况下先执行父进程。

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

int main(int argc,char *argv[])
{
        pid_t pid;

        printf("this is current pid :%d\n",getpid());
        pid=fork();
        if(pid==0)
        {
                printf("this is child pid :%d\t,my parent pid is %d \n",getpid(),getppid());
        }
        else if(pid !=-1)//子进程的值
        {
                printf("this is parent pid :%d \n",getpid());
                sleep(1);
        }
        else{
                printf("error\n");
        }


        return 0;
}

./pid(没有加sleep)
this is current pid :24345
this is parent pid :24345
linux@ubuntu:~/shl/sy_linux$ this is child pid :24346 ,my parent pid is 1
父进程的pid居然是1?再看前面可知,父进程已经return结束了,子进程才开始执行。

再此程序父进程加一段延时或者使用wait()

linux@ubuntu:~/shl/sy_linux$ ./pid
this is current pid :24363
this is parent pid :24363
this is child pid :24364 ,my parent pid is 24363

这样就得到我们想要的效果了。
使用wait()来等待子进程结束,并获取返回值

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

int main(int argc,char *argv[])
{
        pid_t pid;
        int ret;

        printf("this is current pid :%d\n",getpid());
        pid=fork();
        if(pid==0)
        {
                printf("this is child pid :%d\t,my parent pid is %d \n",getpid(),getppid());
        }
        else if(pid !=-1)//子进程的值
        {
                printf("this is parent pid :%d \n",getpid());
                wait(&ret);
                printf("ret= %d\n",ret);

        //        sleep(1);
        }
        else{
                printf("error\n");
        }


        return 0;
}

ret的值其实也就是子进程return回的值。
wait()其实有2种,在有多个子进程进行运算时,使用waitpid()也可以选择对应的子进程来结束。
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options)

waitpid()函数与调用 wait()的区别是 waitpid()等待由参数 pid 指定的子进程退出。
其中参数 pid 的含义与取值方法如下:
参数pid<-1时,等待进程组ID等于pid的绝对值的子进程退出。
参数pid=0时,等待进程组ID等于当前进程的进程组ID的子进程退出。
参数pid>0时,等待进程ID等于参数pid的子进程退出。
参数pid=-l时,等待任何子进程退出,相当于调用wait()。

参数 options 的让 wait()的使用更加灵活, 下面宏定义是 option 的可选值及含义,option 可以多个宏使用位或运算获得:
WNOHANG:该选项要求如果没有子进程退出就立即返回。
WUNTRACED:对已经停止但未报告状态的子进程,该调用也从等待中返回和报告状态。
如果status不是空,调用将使status指向该信息。
waitpid()将返回退出的子进程的 PID。
如果设置了 WNOHANG 选项没有子进程退出就返回 0。
如果发生错误时返回-1.
发生错误时,可能设置的错误代码如下。
    ECHILD:该调用指定的子进程pid不存在,或者不是发出调用进程的子进程。
    ElNVAL:参数options无效。
    ERESTARTSYS: WNOHANG没有设置并且捕获到SIGCHLD或其它未屏蔽信号。


#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
int main(int argc, char **argv)
{
      int status;
      pid_t pid;
      pid_t pid_c;
      pid=fork();
      if(pid ==0){
       printf("child process will sleep 5 seconds.\n");
        sleep(5);
      printf("child PID[% d]will exit with status3.\n",getpid());
         exit(3);
        }
        else if(pid!=-1){
                  do{
                     pid_c = waitpid(pid,&status,WNOHANG);
                     if(pid_c==0){
                     printf("Not child process exit\n");
                     sleep(1);
                   }
              }while(pid_c==0);
                if(WIFEXITED(status)){
                /*如果WIFEXITED返回非零值*/ 
                 printf("the child process % d exit normally.\n",pid_c);
              printf("the return code is %d.\n",WEXITSTATUS(status));
               }    
                else{
                  /*如果WIFEXITED返回零*/
                   printf("the child process % d exit  abnormally.\n",pid_c);
                    }
              }else{
                      printf("There was an error with forking!\n");
              }
              return 0;
} 
//很少用这个,用到再回来看吧,大多还是用线程的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值