进程概念

进程:
一、概念:是一个正在执行的可执行程序实例。
二、构成:进程信息存放在进程控制块PCB的数据结构中。

三、数据结构:
在Linux中描述进程的数据结构是task_struct;
task_struck是Linux内核中的一种数据结构,包含着进程信息存放在内存中。

task_struct //内容
{
1、标识符:pid ,ppid 进程的唯一标识符,用于区分其它进程
2、状态:任务状态,退出码,退出信号
3、优先级:相对其它进程的优先级
4、程序计数器:程序中将要执行下一条指令的地址
5、内存指针:程序代码和数据相关的指针,还有其它进程共享内存块的指针
6、上下文数据:进程执行时处理器中的寄存器信息(用于进程恢复,休学例子)
7、I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
8、记账信息:包括处理器的时间总和,使用的时钟总数,时间限制,记账号等。
9、其它信息
};

四、进程状态:
R—-就绪状态(运行)—进程运行
S—-睡眠—-进程睡眠时(sleep)
D—-磁盘休眠(不可中断睡眠)
T—-停止—-给进程发送:kill -19 进程pid ,此时(R/S)进程变为停止态,发送SIGCONT继续运行。
t—-跟踪状态(等待跟踪进程对它的控制)
X—-死亡状态(进程正常退出,异常退出等)
Z—-僵尸状态

僵尸进程:
子进程先退出,且父进程未回收子进程的退出信息,导致子进程变为僵尸进程。
僵尸进程不可被直接杀死,只能通过杀死父进程,杀死子进程。
原因:父进程退出后,父进程会获取子进程状态信息,回收子进程资源。
僵尸进程代码:

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

int main()
{
    pid_t pid = fork();

    if(pid > 0)
    {
        printf("父进程:%d\n",getpid());
        while(1)
            sleep(2);
    }

    if(pid == 0)
        printf("子进程:%d\n",getpid());

    return 0;
}

//僵尸进程:
//子进程先退出,且父进程未回收子进程的退出信息,导致子进程变为僵尸进程。
//僵尸进程不可被直接杀死,只能通过杀死父进程,杀死子进程。
//原因:父进程退出后,父进程会获取子进程状态信息,回收子进程资源。

//孤儿进程:
//父进程先退出,子进程未退出变为孤儿进程。
//孤儿进程会被1号进程领养。由1号进程控制,获取信息,回收资源。

孤儿进程:
父进程先退出,子进程未退出变为孤儿进程。
孤儿进程会被1号进程领养。由1号进程控制,获取信息,回收资源。
孤儿进程代码:

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

int num = 0;
int main()
{
    pid_t pid = fork();
    if(pid == 0)
    {
        num = 100;
        while(1)//每隔2s打印一次子进程信息
        {
            printf("子进程num = %d pid = %d ppid = %d\n",num,getpid(),getppid());
            sleep(2);//父进程退出后子进程变为孤儿进程,ppid = 1
        }
    }

    if(pid > 0)
    {
        printf("父进程num = %d pid = %d ppid = %d\n",num,getpid(),getppid());
        sleep(3);//3s后父进程退出
    }

    if(pid < 0)
    {
        perror("fork");
        exit(-1);
    }
    return 0;
} 

//查看进程信息: ps axu | grep 进程名
//退出(杀死)进程:kill -9 进程pid

五、进程常见指令
查看进程设置指令:kill -l;
杀死进程:kill -9 进程pid
查看进程优先级:ps -l 或 ps -elf
查看进程:ps axu 或top(类似任务管理器)

六、组织进程方式:
所有运行的进程都以task_struct链表的形式存放在内存中。

七、进程的性质:
并发性:多个进程在同一时间段内,同时执行,访问共享资源采用使程切换实现。
并行性:多个进程在多个cpu上,同一时刻同时运行。
竞争性:进程数目多于资源数,所以进程之间存在竞争的属性,为了高效的完成任务,便有了优先级。
独立性:多进程之间,进程独享资源,互不干扰。

八、同步与互斥:
进程互斥:多个进程同时访问共享资源,但资源只能分配给一个进程使用,所产生的现象。
进程同步:多个进程相互协作完成同一任务。

九、创建进程:fork(),vfork()
1、创建子进程:父进程会将自己的PCB,代码,缓冲区拷贝一份给子进程。
2、父,子进程的pid,ppid不同。
3、父进程设置的文件锁不会被子进程继承
4、子进程未处理的闹钟会被清除
7、子进程的未处理信号集设置为空。

注:父子进程打开同一文件:父,子进程的表项各自独立,但共用一个文件,对文件操作存在干扰。
子进程关闭文件,并不是直接关闭,而是计数器减1,计数器为0时才关闭文件。

fork创建子进程:
1、fork创建的子进程有两个返回值。
父进程返回子进程的pid,子进程返回0
2、子进程以父进程为模板(PCB,数据,代码),父子进程代码共享,数据各自开辟空间私有一份(采用写实拷贝)
通常父子代码共享,父子不在写操作时,数据也是共享的,当任意一方写操作时,便以写时拷贝的方式各自私有一份数据

父进程—–虚拟地址—–页表映射—–物理地址(父)
子进程—–虚拟地址—–页表映射—–物理地址(子)
父子进程各种有一个虚拟地址(通常4G)和页表,所以父子进程可能存在相同的地址(虚拟)。但数据可能不相同(数据存在物理内存中)。
父子进程数据不写操作时,指向同一物理地址。写操作时,子进程会将父进程的数据拷贝一份下来,在进行写操作。

3、fork成功返回子进程的pid,失败返回-1。
失败原因:1、系统中线程太多,达到最大值
2、用户线程超过了限制。
4、fork之后父子进程继续执行,谁先执行由调度器决定(通常子进程执行3s后父进程再执行)
5、注意缓冲区问题,父进程会将缓冲区的内容拷给子进程。
若fork之后,有输出:
未进行行刷新—-父进程的缓冲区拷给子进程,所以有两次输出
进行行刷新—-父子进程竞争缓冲区,入无延时有一次输出,有延时两次输出。

行缓冲:将内容直接向显示器上输出,按行刷新缓冲区。
全缓冲:将内容重定向写到其它文件中

printf条件显示:
(1)、使用’\n’;
(2)、调用:fflush(stdout);
(3)、缓冲区满了
(4)、遇到scanf获取缓冲区
(5)、进程或线程退出

6、无条件限制时,每遇到一个fork进程数扩大二倍。
7、父子进程相对独立,各自拥有代码,数据,内存空间,栈帧结构等。执行不影响其它进程的数据,栈帧等。

vfork创建进程:
1、不会拷贝内存空间,就算写时也不拷贝。共用一个页表和内存空间。
2、父进程在子进程执行完之后才执行。
3、必须使用exec或exit退出进程,不可使用return
原因:父子进程共用一块内存空间,共用一个栈帧结构。当子执行return后函数栈帧被销毁,父进程无栈帧或栈帧破坏,此时再执行父进程导致出错。
4、建议不要使用vfork创建进程,容易出错。

注:
若父进程先退出,子进程未退出,子进程变为孤儿进程,孤儿进程由1号进程领养,管理和回收子进程的资源。
若子进程先退出,且父进程未接收子进程的状态,管理子进程,则子进程变为僵尸进程。
僵尸进程有内存泄漏的危险。
僵尸进程不可被杀死:kill -9 pid也不可杀死
防止产生僵尸进程方法:进程等待

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值