Linux Day09

目录

一、进程替换

二、Linux信号的使用

[2.1 kill() 发送信号](#2.1 kill() 发送信号)

[2.2 signal() 改变进程对信号的响应方式](#2.2 signal() 改变进程对信号的响应方式)

[2.3 处理僵死进程](#2.3 处理僵死进程)

[2.3.1 在信号处理函数中调用wait](#2.3.1 在信号处理函数中调用wait)

[2.3.2 Linux特有的](#2.3.2 Linux特有的)

[2.3.3 结果](#2.3.3 结果)


一、进程替换

linux上创造一个新进程,没有create创建方法,而是通过fork+exec系列,先将进程复制一份,将子进程替换成另外一个进程,这样就相当于创建一个进程

ps -f和bash没有任何关系,为什么ps -f的父进程是bash,因为bash将自己复制了一份,然后将ps -f替换了它的子进程,从而有了创造了该指令。

#include <unistd.h>
exec 系类方法介绍以 execl 为例:
/*
*path:新替换的程序的路径名称
*arg :传给新程序主函数的第一个参数,一般为程序的名字
*arg 后面是剩余参数列表,参数个数可变,必须以空指针作为最后一个参数
*/
i nt execl( const char * path, const char * arg,...);
int execlp( const char * file, const char * arg,...);
int execle( const char * path, const char * arg,..., char * const envp\[\]);
int execv( const char * path, char * const argv\[\]);
int execvp( const char * file, char * const argv\[\]);
int execve( const char * path, char * const argv\[\], char * const envp\[\]);

bash 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>
#include<string.h>
#include <sys/wait.h>
int main(int agrc,char*argv[],char*envp[]){
    printf("main pid=%d,ppid=%d\n",getpid(),getppid());
    pid_t pid=fork();
    assert(pid!=-1);
    if(pid==0)
    {
        printf("child pid=%d,ppid=%d\n",getpid(),getppid());
        char*myenvp[10]={"MYSTR=hello"};
        execl("/bin/ps","ps","-f",(char*)0);
        execlp("ps","ps","-f",(char*)0);
        execle("/usr/bin/ps","ps","-f",(char*)0,myenvp);

        char* myargv[]={"ps","-f",0};
        execv("/usr/bin/ps",myargv);
        execvp("ps",myargv);
        execve("/usr/bin/ps",myargv,envp);
        printf("execl error");
        exit(0);
    }
    wait(NULL);
    exit(0);
}

结果

二、Linux信号的使用

信号是系统响应某个条件而产生的事件,进程接收到信号会执行相应的操作。

信号的值在系统源码中的定义如下:

  1. #define SIGHUP 1
  2. #define SIGINT 2 //键盘按下 Ctrl+c 时,会产生该信号
  3. #define SIGQUIT 3
  4. #define SIGILL 4
  5. #define SIGTRAP 5
  6. #define SIGABRT 6
  7. #define SIGIOT 6
  8. #define SIGBUS 7
  9. #define SIGFPE 8
  10. #define SIGKILL 9 //该信号的响应方式不允许改变
  11. #define SIGUSR1 10
  12. #define SIGSEGV 11
  13. #define SIGUSR2 12
  14. #define SIGPIPE 13 //读端关闭的描述符,写端写入时产生,该信
    号会终止程序
  15. #define SIGALRM 14
  16. #define SIGTERM 15 //系统 kill 命令默认发送的信号
  17. #define SIGSTKFLT 16
  18. #define SIGCHLD 17 //子进程结束后,会默认给父进程发送该信
    号
  19. #define SIGCONT 18
  20. #define SIGSTOP 19
  21. #define SIGTSTP 20
  22. #define SIGTTIN 21
  23. #define SIGTTOU 22
  1. #define SIGURG 23

2.1 kill() 发送信号

kill() 可以向指定的进程发送指定的信号:
int kill(pid_t pid, int sig);
pid > 0 指定将信号发送个那个进程
pid == 0 信号被发送到和当前进程在同一个进程组的进程
pid == -1 将信号发送给系统上有权限发送的所有的进程
pid < -1 将信号发送给进程组 id 等于 pid 绝对值,并且有权限发送的所有的进程。
sig 指定发送信号的类型。

bash 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
int main(int argc,char*argv[])
{
    if(argc!=3)
    {
        printf("argc err\n");
        exit(1);
    }
    int pid=atoi(argv[1]);
    int sig=atoi(argv[2]);
    if(kill(pid,sig)==-1)
    {
        printf("kill err\n");
    }
    exit(0);
}

2.2 signal() 改变进程对信号的响应方式

bash 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
void fun_sig(int sig){
    printf("sig=%d",sig);
}
int main(){
    signal(SIGINT,fun_sig);
    while(1){
        printf("main run\n");
        sleep(1);
    }
    exit(0);
}

结果:

ctrl+c的信号值为2,与内核达成协议,当有ctrl+c时执行fun_sig()函数。

如果想要结束该进程 :

1.新建一个窗口,查看该进程编号,结束该进程

2.Ctrl +/

signal(SIGINT,SIG_IGN);忽略 ,如果再ctrl+c,系统不会终止,会继续执行

signal(SIGINT,SIG_DFL);默认,如果再ctrl+c,系统终止

signal(SIGINT,fun_sig);

bash 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
void fun_sig(int sig){
    printf("sig=%d\n",sig);
    signal(sig,SIG_DFL);
}
int main(){
   // signal(sig,SIG_DFL);//默认
   // signal(sig,SIG_IGN);//忽略
    signal(SIGINT,fun_sig);//自定义
    while(1){
        printf("main run\n");
        sleep(1);
    }
    exit(0);
}

结果

当第一次使用ctrl+c时,调用自定义函数,返回该信号的值,第二次使用ctrl+c调用系统默认的,结束了该进程。

2.3 处理僵死进程

2.3.1 在信号处理函数中调用wait

bash 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
#include<sys/wait.h>
void fun_sig(int sig)
{
    printf("sig=%d\n",sig);
    wait(NULL);
}
int main()
{
    char*s=NULL;
    int n=0;
    signal(SIGCHLD,fun_sig);
    pid_t pid=fork();
    if(pid==-1){
        exit(1);
    }
    if(pid==0)
    {
        s="child";
        n=3;
    }
    else
    {
        s="parent";
        n=7;
    }
    int i=0;
    for(;i<n;i++){
        printf("s=%s,pid=%d\n",s,getpid());
        sleep(1);
    }
    exit(0);

}

2.3.2 Linux特有的

signal(SIGCHLD,SIG_IGN);

bash 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>
#include<sys/wait.h>
void fun_sig(int sig)
{
    printf("sig=%d\n",sig);
    wait(NULL);
}
int main()
{
    char*s=NULL;
    int n=0;
    signal(SIGCHLD,SIG_IGN);
    pid_t pid=fork();
    if(pid==-1){
        exit(1);
    }
    if(pid==0)
    {
        s="child";
        n=3;
    }
    else
    {
        s="parent";
        n=7;
    }
    int i=0;
    for(;i<n;i++){
        printf("s=%s,pid=%d\n",s,getpid());
        sleep(1);
    }
    exit(0);

}

2.3.3 结果

相关推荐
GeW1 小时前
新质生产力路线图Linux、数据库、国产化替代一次讲透
linux
aningx3 小时前
cachyos 从 GRUB 切换到 rEFInd
linux
第404号工位5 小时前
40块钱二手瘦客户端,如何跑满家庭物联网中枢?(拒绝Docker爆盘实录)
linux·架构·node.js
对象存储与RustFS5 小时前
网盘限速逼你开会员?用 RustFS 自己搭一个不限速的“私人网盘
服务器·后端·docker
骑着蜗牛撵大象3276 小时前
Linux 进程间通信之管道:从 pipe() 的内核语义到 FIFO 落地排错
android·java·linux·系统编程·fifo·管道·进程间通信
众壹新能源科技7 小时前
逆变器自带无功不够用,加装5MVar SVG后功率因数从0.85回到0.99
运维·人工智能·自动化
..Dauntless..7 小时前
【Linux】一切皆文件和缓冲区
linux·运维·服务器
裕晟资质规划7 小时前
三类资质变更报告时限差在哪?军工 15 日、集成印制 10 日
大数据·服务器·网络
QMCY_jason7 小时前
x86 ubuntu2204 无gui 安装 openeuler 2203 aarch64版本
linux·运维·服务器
重生之小比特7 小时前
【Linux系统】12 进程程序替换 自定义Shell 命令行解释器
linux·运维·服务器