ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

CSAPP Shell Lab

2020-12-26 23:31:50  阅读:318  来源: 互联网

标签:CSAPP Shell int pid 阻塞 Lab 终止 信号 进程


知识总结

一、异常和进程
1、异常,中断的一种类型:
在这里插入图片描述
故障: 错误引起,如缺页,除0
陷阱:”故意的异常“,目的是使用系统调用
终止:致命错误,如硬件损坏

2、创建子进程 —— fork()函数:
作用:创建子进程,返回两次,父进程返回创建子进程的pid,子进程返回0

3、僵尸进程:
进程有三种状态:运行、停止、终止;进程终止时仍占用系统资源,终止但未被回收的子进程成为僵尸进程。
子进程的回收交由父进程执行,接收子进程的退出状态,内核删除其信息;如果父进程先于子进程终止,则交由所有进程的祖先–init负责回收。
创建僵尸进程:

  if (fork() == 0){
       cout << "child PID = "<<getpid() <<endl;
       exit(0);  //子进程将成为僵尸进程
    }
      else {
        cout << "parent PID = " << getpid() << endl;
        while(1) ;
    }

在这里插入图片描述
可以用kill + 进程号杀死父进程,init()会回收子进程

4、避免僵尸进程——>进程的回收,wait()和waitpid()
(1)wait:
int wait(int *child_status)
作用:挂起当前进程,直到一个子进程终止,返回子进程的pid,不能明确指定等待哪个子进程退出。
(2)waitpid:
默认挂起调用进程的执行,直到等待集合中的一个子进程终止,返回终止子进程的进程号。
当回收完所有子进程后,waitpid会将errno设置为ECHILD。

pid_t waitpid(pid_t pid,int * status,int options);
//pid: (1)若>0,等待集合是一个单独的子进程,进程ID等于pid;(2)-1,则等待集合是由父进程的所有子进程
/*status:一般传地址(&status),可用几个宏检查子进程退出的状态信息
(1)WIFEXITED:子进程通过调用exit()正常终止
...
/*options:默认写0,也可以填写下面的宏修改默认行为
(1)WNOHANG:若等待集合中的任何子进程都没有终止,则立即返回
(2)WUNTRACED:挂起调用进程,直到集合中一个进程终止,或集合中一个被停止的进程收到SIGCONT信号开始重新执行
*/

进程回收示例:

   pid_t pid;
    int status;
    if(fork()==0)
    {
        cout << getpid() <<endl;
        exit(0);
    }
    //子进程被回收
    while(pid = waitpid(-1,&status,0) > 0)
    {
        if(WIFEXITED(status))cout << "OK" <<endl;//如果子进程通过exit()正常终止
    }
    printf("I am father");
    while(1);

二、信号
1、什么是信号? linux的一种提醒机制,windows下称为消息
常用信号:
在这里插入图片描述

2、待处理信号与阻塞信号:
待处理信号:发生但没有被接收的信号
阻塞信号:阻塞的信号不会被进程接收,直到进程取消阻塞

3、注册信号处理程序:

void SIGINT_handler( int sig){
   printf("Hello World!\n");
}
int main(int argc, const char * argv[]) {
  //注册SIGINT信号处理函数
  if (signal(SIGINT, SIGINT_handler) == SIG_ERR)
      printf("signal error!\n");
  while(1);
}

在这里插入图片描述

4、信号阻塞
(1)内核默认则塞与当前正在处理信号类型相同的待处理信号
(2)sigprocmask:改变当前阻塞的信号集合,具体取决于how

 int sigprocmask(int how,const sigset_t*set,sigset_t *oldset);    

新信号集取决于set与oldset,how有三种取值
1、SIG_BLOCK:向阻塞信号集合中添加信号
2、SIG_UNBLOCK:在阻塞集合中去除信号
3、SIG_SETMASK:阻塞集合 = 信号

示例:

//使用sigprocmask阻塞SIGINT信号,效果为ctrl+C进程不会终止
void SIGINT_handler( int sig){
   printf("Hello World!\n");
}
int main(int argc, const char * argv[]) {
  sigset_t mask, prev_mask;
  sigemptyset(&mask);
  sigaddset(&mask,SIGINT);
  sigprocmask(SIG_BLOCK,&mask,&prev_mask);
  while(1){};
}

5、管道与进程组
(1)作业:指对shell命令行进行求值而创建的进程
(2)管道:‘|’操作符,作用为连接两个进程,将左边进程的输出作为右边进程的输入
(3)进程组:linux系统会为每个作业创建一个单独的进程组

7、编写并发程序的几个tips
(1)使用异步信号安全的函数,如write
(2)保存和恢复errno
(3)在访问共享数据结构时,阻塞所有的信号
(4)用volatile声明全局变量:
编译器为了提高执行速度,一般会将变量值缓存到寄存器中,对于多线程的程序,可能会导致修改不可见。使用volatile声明变量,则等同于告诉编译器不要在寄存器中缓存,多线程访问时都会从内存中读取。
(5)使用sig_atomic_t声明变量:保证对该变量的操作都是原子操作

8、利用SIGCHILD优化进程回收:
因为子进程终止会发送SIGCHILD信号给父进程,因此父进程当收到信号时再回收效率更高,不必显式等待,但需要注意,信号不会排队!
在这里插入图片描述

9、如何消除竞争?
在一个场景中,父进程创建子进程需要addjob,子进程终止后父进程调用信号处理函数回deletejob,那么在addjob和deletejob之间存在竞争关系。
一种消除竞争的方法就是在fork()创建子进程前阻塞sigchild信号,在addjob之后再取消阻塞。

CSAPP shell Lab

标签:CSAPP,Shell,int,pid,阻塞,Lab,终止,信号,进程
来源: https://blog.csdn.net/ToryYang/article/details/109017840

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有