系统编程1——进程

程序:一段代码
进程:正在运行的程序,资源分配的最小单元!!!
程序与进程的区别:
1.进程是动态的,程序是静态的:
程序是有序代码的集合;进程是程序的执行。通常进程不可在计算机之间迁移;而程序通常对应着文件、静态和可以复制
2.进程是暂时的,程序使长久的:
进程是一个状态变化的过程,程序可长久保存
3.进程与程序组成不同:
进程的组成包括程序、数据和进程控制块(即进程状态信息)
4.进程与程序的对应关系:
通过多次执行,一个程序可对应多个进程;通过调用关系,一个进程可包括多个程序。

Linux下如何查看进程:
ps(Process Status的缩写):显示当前时刻的进程
top:动态显示进程信息

ps -e 或 -a:显示所有进程
ps -l:用来观察自己的bash相关的进程
ps -f:显示程序间的关系
ps -aux 显示所有包含其他使用者的行程
ps的显示信息:
1.F:代表这个程序旗标(process flags),说明这个程序的总结权限,常见号码有:
    若为4 表示此程序的权限为root ;
    若为1则表示此子程序仅进行复制(fork)而没有实际执行(exec)。
2.S:代表这个进程的状态 (STAT),主要的状态有:
    R (Running):该进程正在运行;
    S (Sleep):该进程正在睡眠,可被唤醒。
    D :不可被唤醒
    T :停止状态(stop);
    Z (Zombie):僵尸进程。
3. ................

一个进程的生命周期:
创建 ——> 运行——> 撤销

Linux系统是一个多进程的系统,它的进程之间具有并行性、互不干扰等特点。
也就是说,每个进程都是一个独立的运行单位,拥有各自的权利和责任。其中,各个进程都运行在独立的虚拟地址空间,因此,即使一个进程发生异常,它也不会影响到系统中的其他进程。

Linux中的进程包含3个段,分别为“数据段”、“代码段”和“堆栈段”。
“数据段”存放的是全局变量、常数以及动态数据分配的数据空间;
“代码段”存放的是程序代码的数据。
“堆栈段”存放的是子程序的返回地址、子程序的参数以及程序的局部变量等。 


相关系统调用函数介绍:
1.
#include <sys/types.h> 
#include <unistd.h>
pid_t getpid(void)        获取本进程ID。
pid_t getppid(void)        获取父进程ID

例:
int main(void)
{
   printf( "PID = %d\n", getpid() );
   printf( “PPID = %d\n”, getppid() );
   return 0;
}

2.
#include <unistd.h>
pid_t fork(void)
功能:创建子进程
fork的奇妙之处在于它被调用一次,却返回两次,它可能有三种不同的返回值:

例:
#include <sys/types.h>
#include <unistd.h>
int main()
    {
        pid_t pid;
        /*此时仅有一个进程*/
        pid=fork();
              /*此时已经有两个进程在同时运行*/
        if(pid<0)
            printf("error in fork!");
        else if(pid==0)
            printf("this is child process, ID is %d\n",getpid());
        else
            printf("this is parent process,ID is %d\n",getpid());
}

fork的功能时在当前的进程下创建一个子进程,这个子进程的父进程就是当前这个进程。
这两个进程名字相同,但是进程号不同差一。
fork的返回值如果为0;就是子进程。父进程返回子进程的进程号。调用失败返回非0值。
fork使子进程复制一份父进程的虚拟内存作为自己的内存地址。
子进程的数据空间、堆栈空间都会从父进程得到一个拷贝,而不是共享。


3.
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void)

功能:创建子进程
vfork与fork的区别:
(1).fork:子进程拷贝父进程的数据
  vfork:子进程与父进程共享数据

(2).fork:父、子进程的执行次序不确定
  vfork:子进程先运行,父进程后运行
  
  
4.exec函数族
#include<unistd.h>
int execl(const char * path,const char * arg1, ...)
    参数:
    path:被执行程序名(含完整路径)。
    arg1 – argn: 被执行程序所需的命令行参数,含程序名。以空指针(NULL)结束。

#include<unistd.h>
int execv (const char * path, char * const argv[ ])
    参数:
    path:被执行程序名(含完整路径)。
    argv[]: 被执行程序所需的命令行参数数组。

5.等待进程
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait (int * status)
功能:阻塞该进程,直到其某个子进程退出。

#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid (pid_t pid, int * status, int options)
功能:
会暂时停止目前进程的执行,直到有信号来到或子进程结束


6.进程退出
表头文件: #include<stdlib.h>
定义函数: void exit(int status);
函数说明:
exit()用来正常终结目前进程的执行,并把参数status返回给父进程,而进程所有的缓冲区数据会自动写回并关闭未关闭的文件。


僵尸进程:
僵尸进程指的是那些虽然已经终止的进程,但仍然保留一些信息,等待其父进程为其收尸。
如何产生?
如果一个进程在其终止的时候,自己就回收所有分配给它的资源,系统就不会产生所谓的僵尸进程了

僵尸进程产生的过程:
1. 父进程调用fork创建子进程后,子进程运行直至其终止,它立即从内存中移除,
但进程描述符仍然保留在内存中(进程描述符占有极少的内存空间)。
2. 子进程的状态变成EXIT_ZOMBIE,并且向父进程发送SIGCHLD 信号,
父进程此时应该调用 wait() 系统调用来获取子进程的退出状态以及其它的信息。
在 wait 调用之后,僵尸进程就完全从内存中移除。
3. 因此一个僵尸存在于其终止到父进程调用 wait 等函数这个时间的间隙,一般很快就消失,
但如果编程不合理,父进程从不调用 wait 等系统调用来收集僵尸进程,那么这些进程会一直存在内存中。

猜你喜欢

转载自blog.csdn.net/sinat_39440759/article/details/81748474
今日推荐