Linux进程操作简述

1.进程标识符

每个进程都有一个非负整数表示的唯一ID,叫做pid
pid = 0;称为进程交换。作用—进程调度
pid = 1;init进程。作用—系统初始化

编程调用getpid函数获取自身的进程标识符
getppid获取父进程的进程标识符

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

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

	printf("my pid is %d\n",pid);


	return 0;
}

2.fork函数创建一个进程

函数原型

SYNOPSIS
       #include <unistd.h>

       pid_t fork(void);

返回值 pid_t

fork函数调用成功返回两次:
返回值为0,代表当前进程是子进程
返回值为非负数,代表当前进程为父进程
返回失败返回-1

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

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

        fork();

        if(pid == getpid()){
                printf("this is father,pid = %d\n",getpid());
        }else{
                printf("this is child,pid = %d\n",getpid());
        }

        return 0;
}

运行结果:

this is father,pid = 3339
this is child,pid = 3340
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
        pid_t pid;
        pid_t pid2;

        pid = getpid();
        printf("before fork pid = %d\n",pid);

        fork();

        pid2 = getpid();
        printf("after fork pid = %d\n",pid2);

        if(pid == pid2){
                printf("this is father,pid = %d\n",getpid());
        }else{
                printf("this is child,pid = %d\n",getpid());
        }

        return 0;
}
运行结果:
before fork pid = 3441
after fork pid = 3441
this is father,pid = 3441
after fork pid = 3442
this is child,pid = 3442

就是说fork以后,父进程和子进程都会执行下面的代码,子进程和父进程走不一样的分支

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

int main()
{
        pid_t pid;

        printf("father id = %d\n",getpid());

        pid = fork();

        if(pid >0){
                printf("this is father,pid = %d,fork return = %d\n",getpid(),pid);
        }else if(pid == 0){
                printf("this is child,pid = %d,fork return  = %d\n\n",getpid(),pid);
        }



        return 0;
}

运行结果:
father id = 3557
this is father,pid = 3557,fork return = 3558
this is child,pid = 3558,fork return  = 0

pid值为0代表是子进程,大于0代表是父进程。

子进程拷贝了一份父进程的内容
在早期的Linux底下,子进程会拷贝父进程存储空间中的正文,初始化的数据,把堆栈,命令行参数进行拷贝,以及打开的文件io流等等全部进行拷贝
后面Linux技术的内容更新,不一定会把这些内容进行拷贝,而是进行写时拷贝,假设一个数据,如果后面的代码子进程没有对该数据进行改变的话,采用共享的方式,共享这个内存空间,不一定要做拷贝,这个就是大致上的写实拷贝

3.fork创建一个子进程的一般目的

(1)一个父进程希望复制自己,使父,子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待客户端的服务请求。当这种情况到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。
(2)一个进程要执行一个不同的程序。这对shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec。

模拟服务器接收客户端服务请求

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

int main()
{
        pid_t pid;

        int data = 0;

        while(1){
                printf("please input a data:\n");
                scanf("%d",&data);
                if(data == 1){

                        pid = fork();
                        if(pid > 0){

                        }
                        else if(pid == 0){

                                while(1){
                                        printf("do net request,pid = %d\n",getpid());

                                        sleep(3);
                                }
                        }
                }else{
                        printf("wait,do nothing\n");
                }
        }

        return 0;
}
运行结果:
please input a data:
2
wait,do nothing
please input a data:
3
wait,do nothing
please input a data:
1
please input a data:
do net request,pid = 3680
do net request,pid = 3680
4
wait,do nothing
please input a data:
do net request,pid = 3680
5
wait,do nothing
please input a data:
do net request,pid = 3680
1
please input a data:
do net request,pid = 3681
do net request,pid = 3680
do net request,pid = 3681
do net request,pid = 3680
1
please input a data:
do net request,pid = 3682
do net request,pid = 3681
do net request,pid = 3680
do net request,pid = 3682
do net request,pid = 3681
do net request,pid = 3680
do net request,pid = 3682

4.vfork函数创建进程

vfork函数和fork函数的区别
(1)vfork直接使用父进程存储空间,不拷贝。
(2)vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行。

用代码显示这两个函数的区别:
(1)fork函数

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

int main()
{
        pid_t pid;

        pid  = fork();

        if(pid > 0){
                while(1){
                        printf("this is father print,pid = %d\n",getpid());
                        sleep(1);
                }
        }
        else if(pid == 0){
                while(1){
                        printf("this is child print,pid = %d\n",getpid());
                        sleep(1);
                }
        }


        return 0;
}

运行结果:
this is father print,pid = 3799
this is child print,pid = 3800
this is father print,pid = 3799
this is child print,pid = 3800
this is father print,pid = 3799
this is child print,pid = 3800
this is father print,pid = 3799
this is child print,pid = 3800
this is father print,pid = 3799
this is child print,pid = 3800
this is father print,pid = 3799
this is child print,pid = 3800
this is father print,pid = 3799
this is child print,pid = 3800
this is father print,pid = 3799
this is child print,pid = 3800
父子进程都会执行,互相争夺CPU,不一定是一人一次,取决于进程的调度,fork函数的特点。

(2)vfork函数

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

int main()
{
        pid_t pid;

        pid  = vfork();

        if(pid > 0){
                while(1){
                        printf("this is father print,pid = %d\n",getpid());
                        sleep(1);
                }
        }
        else if(pid == 0){
                while(1){
                        printf("this is child print,pid = %d\n",getpid());
                        sleep(1);
                }
        }


        return 0;
}
运行结果:
this is child print,pid = 3827
this is child print,pid = 3827
this is child print,pid = 3827
this is child print,pid = 3827
this is child print,pid = 3827
this is child print,pid = 3827
this is child print,pid = 3827
this is child print,pid = 3827
一直都在运行子进程

(3)vfork函数例子

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

int main()
{
        pid_t pid;
        int cnt = 0;

        pid  = vfork();

        if(pid > 0){
                while(1){
                        printf("cnt = %d\n",cnt);
                        printf("this is father print,pid = %d\n",getpid());
                        sleep(1);
                }
        }
        else if(pid == 0){
                while(1){
                        printf("this is child print,pid = %d\n",getpid());
                        sleep(1);
                        cnt++;
                        if(cnt == 3){
                                exit(0);		0代表其推出状态
                        }
                }
        }


        return 0;
}

运行结果:
this is child print,pid = 3876
this is child print,pid = 3876
this is child print,pid = 3876
cnt = 3
this is father print,pid = 3875
cnt = 3
this is father print,pid = 3875
cnt = 3
this is father print,pid = 3875
cnt = 3
this is father print,pid = 3875
cnt = 3
this is father print,pid = 3875

子进程运行次数达到,退出,运行父进程,因为直接使用的是父进程的存储空间,所以cnt的值被改变,子程序退出时,
需要用一个好的方式推出,否则会破坏变量。

5.进程推出

进程推出分为正常推出和异常推出

正常推出
1.Main函数调用return
2.进程调用exit(),标准库
3.进程调用_exit()或者_Exit(),属于系统调用
补充:
1.进程最后一个线程返回
2.最后一个线程调用pthread_exit

异常推出
1.调用abort
2.当进程收到某些信号时,如ctrl+C
3.最后一个线程对取消(cancellation)请求做出响应

6.父进程等待子进程退出

子进程正常退出有5种方式,异常推出3种。

父进程等待收集子进程的退出状态,函数原型

NAME
       wait, waitpid, waitid - wait for process to change state

SYNOPSIS
       #include <sys/types.h>
       #include <sys/wait.h>

       pid_t wait(int *status);
       status参数: 是一个整型数指针
       非空:子进程退出状态放在它所指向的地址中,打印时需要用到宏WEXITSTATUS(status),取子进程正常退出
       的前三种参数的低八位。
       空:不关心退出状态

       pid_t waitpid(pid_t pid, int *status, int options);
       wait使调用者阻塞,waitpid有一个选项options,可以使调用者不阻塞
       对于waitpid函数中的pid参数的作用解释如下:
       pid == -1		等待任一子程序。就这一方面而言,waitpid与wait等效。
       pid  > 0 		等待其进程ID与pid相等的子进程。(用的较多)
       pid == 0		等待其组ID等于调用者ID的任一子进程。
       pid  < -1 		等待其组ID等于pid绝对值的任一子进程。
		
		waitpid的 options常量用的较多的宏:
		WNOHANG :若pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时其返回值为0。

       int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
如果其所有子进程都还在运行,则阻塞。
如果一个子进程已经终止,正等待父进程获取其终止状态,则取得该子进程的终止状态立即返回。
如果它没有任何子进程,则立即出错返回。

小结

基础的东西,会随时修改
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值