【Linux-Day8- 进程替换和信号】

进程替换和信号

问题引入

我们发现 终端输入的任意命令的父进程都是bash,这是因为Linux系统是用fork()复制出子进程,然后在子进程中调用替换函数进行进程替换,实现相关命令。

(1) exec 系列替换过程:pcb 使用以前的只修改,进程实体更换。

进程替换函数

#include <unistd.h>

int execl( const char * path, const char * arg,...);

/*

*path:新替换的程序的路径名称

*arg :传给新程序主函数的第一个参数,一般为程序的名字

*arg 后面是剩余参数列表,参数个数可变,必须以空指针作为最后一个参数

*/

int execlp( const char * file, const char * arg,...);

/*
2.

int execlp( const char * file, const char * arg,...);

/*

*file:新替换的程序的名称

*arg :传给新程序主函数的第一个参数,一般为程序的名字

*arg 后面是剩余参数列表,参数个数可变,必须以空指针作为最后一个参数

*/

int execle( const char * path, const char * arg,..., char * const envp\[\]);

/*

*path:新替换的程序的路径名称

*arg :传给新程序主函数的第一个参数,一般为程序的名字

*arg 后面是剩余参数列表,参数个数可变,必须以空指针作为最后一个参数

*const envp\[\] : 存放环境变量

*/

int execv( const char * path, char * const argv\[\]);

/*

*path:新替换的程序的路径名称

const argv\[\] :存放命令参数的指针数组

*/

int execvp( const char * file, char * const argv\[\]);

/*

*file: 新替换的程序的名称

const argv\[\] :存放命令参数的指针数组

*/

int execve( const char * path, char * const argv\[\], char * const envp\[\]);

/*

*path:新替换的程序的路径名称

const argv\[\] :存放命令参数的指针数组

*const envp\[\] : 存放环境变量

*/

使用模板如下

c 复制代码
#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 \n",getpid() ); 
    assert(pid!=-1);
    if(pid==0)
    {
        printf("child pid=%d,ppid=%d\n",getpid(),getppid());
      //1.  execl("/bin/ps","ps","-f",(char*)0);
      //2.  execlp("ps","ps","-f",(char*)0);
      //3.  execle("/usr/bin/ps","ps","-f",(char*)0,envp);
        char* myargv[]={"ps","-f",0};
      //4.  execv("/usr/bin/ps",myargv);
      //5.  execvp("ps",myargv);
      //6.  execve("/usr/bin/ps",myargv,envp); 
        exit(0);
    } 
    exit(0);
}

Linux 信号的使用

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

与信号有关的系统调用在"signal.h"头文件中有声明

常见信号的值,及对应的功能说明

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

  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
  24. #define SIGURG 23

修改信号的响应方式 -- 调用signal()

typedef void (*sighandler_t)(int); //函数指针类型重命名

**sighandler_t ** signal(int signum, sighandler_t sig_fun)

/*

signum : 处理的信号

sig_fun :处理信号的函数

​ 1.SIG_IGN 忽略

​ 2.SIG_DFL 默认

​ 3.自定义:自己写处理信号的函数

示例代码:

c 复制代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
void fun(int signum)
{
    printf("Call fun \n");
}

int main()
{
    signal(SIGINT,fun);
    while(1)
    {
        sleep(1);
        printf("Hello\n");
    }
    exit(0);
}

运行结果

发送信号 -- kill()

kill() 可以向指定的进程发送指定的信号:

int kill(pid_t pid, int sig);

pid > 0 指定将信号发送个那个进程

pid == 0 信号被发送到和当前进程在同一个进程组的进程

pid == -1 将信号发送给系统上有权限发送的所有的进程

pid < -1 将信号发送给进程组 id 等于 pid 绝对值,并且有权限发送的所有的进程。

sig 指定发送信号的类型。

示例代码:

1.mykill.c

c 复制代码
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>

int main(int argc,char* argv[])
{
    if(argc != 3)
    {
        printf("argc error\n");
        exit(1);
    }
    int pid = atoi(argv[1]);
    int sig = atoi(argv[2]);
    if(kill(pid,sig) == -1)
    {
        printf("kill error\n");
    }
    exit(0);
}

2.test1.c

c 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<unistd.h>
#include<string.h>
#include<signal.h>

void fun(int signum)
{
    printf("signum=%d \n",signum);
    signal(SIGINT,SIG_DFL);
}

int main()
{
    signal(SIGINT,fun);
    while(1)
    {
        sleep(1);
        printf("Hello\n");
    }
    exit(0);
}

用信号处理fork()僵死进程

c 复制代码
#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("end fork\n");
    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);
}
相关推荐
星恒随风28 分钟前
Linux网络编程:应用层协议究竟是什么?从网络计算器到TCP Socket抽象基类完整实现
linux·网络·笔记·tcp/ip
feng_you_ying_li3 小时前
linux之网络层
linux·运维·网络
未来之窗软件服务3 小时前
Linux 运维日志删除的多种方式—东方仙盟
linux·运维·服务器·仙盟创梦ide·东方仙盟
小雉系统3 小时前
BcoreOS实战:用一个升级包,让Rocky Linux跑进Debian服务器
linux·运维·服务器·debian
thethefighter3 小时前
快速预览Word、WPS秒开,支持空格弹窗
linux·word·wps·快速预览·空格弹窗·nhdeepview
用户8351414049494 小时前
把日志和寄存器值喂给AI做故障定位,我的实际问法
linux·ubuntu
Ruiery4 小时前
Linux 6.6内核内存管理深度解析(十七):vmalloc — 内核要“虚拟连续“就够:物理页逐个凑,页表来连
linux·运维·服务器
Escalating_xu4 小时前
【Linux 网络编程】ARP 的具体过程与 ARP 欺骗:一条 IP → MAC 映射,怎样改变数据的去向?
linux·网络·tcp/ip
坚定的共产主义生产设备永不宕机5 小时前
服务器从裸机开始搭建ESXI虚拟机
linux·服务器·网络
刚入门的大一新生5 小时前
Linux-线程封装
linux·运维·服务器