• pause、jobs、setitimer(2)、system v ipc(day12)


    一、pause(2)的使用
    #include <unistd.h>
    int pause(void);
    功能:等待信号的到来
    返回值:
    -1  错误   errno被设置
    只有在信号处理函数执行完毕的时候才返回。
    
    利用所学的知识,编码实现sleep函数的功能。
    unsigned int psleep(unsigned int seconds);
    代码参见    psleep.c
    
    二、信号从产生到处理的全过程
    1、进程正在运行,按下ctrl+c键
    2、ctrl+c是硬件中断,使用进程切换到内核态。
    3、驱动程序将ctrl+c键解释为2号信号
    4、在内核态中将进程的PCB的2号信号设置为1.继续执行
    5、当进程从内核态回到用户态的时候,检测进程的PCB中有哪些信号到达?如果没有信号到达,直接切换回用户态。如果有信号到达,调用信号的相关处理函数。信号处理函数执行完毕的时候,调用sigreturn(2)返回到内核态。继续第五步。
    
    三、可重入函数
    信号处理函数的栈帧是私有的。
    信号处理函数和进程的执行是异步的。
    如果这两条执行路线出现对共享资源的竞争,这事就大了。
    尽量避免竞争。
    使我的函数尽量不去访问栈帧以外的资源。
    如果函数中使用了全局变量、静态的局部变量、malloc的内存。那么这个函数就是不可重入函数。
    可重入函数只能访问栈帧里的内容。如果这个函数只有地洞局部变量,那么这个函数就是可重入函数。
    举例说明  信号处理函数和进程竞争共享资源。
    代码参见  count.c
    
    四、作业
    进程组    有一个或多个进程
    父进程    子进程     孙子进程
    
    作业分为前台作业和后台作业,前台作业只有一个,后台作业有多个。
    按键产生的信号只能发送给前台作业。
    
    将前台作业转换为后台作业
    ctrl+z
    后台作业转换为前台作业
    fg %作业号
    在后台运行作业
    bg  %作业号
    查看后台作业
    jobs
    在作业启动的时候,直接将作业放到后台执行
    作业&
    
    补充一句:
    子进程结束的时候,子进程向父进程发送SIGCHLD信号,父进程收到,就去收尸。
    
    五、使用setitimer(2)设置计时器
    系统计时器做了解
    系统运行一个进程时候,进程消耗的时间包含三部分
    用户时间    进程消耗在用户态的时间
    内核时间    进程消耗在内核态的时间
    睡眠时间    进程消耗在等待I/O、睡眠等不被调度的时间
    内核为系统中的每个进程维护三个计时器
    真实计时器   统计进程的执行时间
    虚拟计时器   统计进程的用户时间
    实用计时器   统计进程的用户时间和内核时间
    
    这三个计时器除了统计功能以外,还可以按照自己的规则,以定时器的方式工作,向进程周期性的发送信号。
    
    利用这个功能设计一个计时器
    setitimer(2)
    #include <sys/time.h>
    int setitimer(int which, const struct itimerval *new_value,
                         struct itimerval *old_value);
    功能:设置定时器的间隔值
    参数:
    which:
    ITIMER_REAL:
    ITIMER_VIRTUAL: 
    ITIMER_PROF:
    
    new_value:指定了定时器的新值
    old_value:保存了定时器的旧值
    返回值:
    0  成功
    -1  错误  errno被设置
    
    ITIMER_REAL:真实   SIGALRM
    ITIMER_VIRTUAL:虚拟  SIGVTALRM
    ITIMER_PROF:实用 SIGPROF
    
    struct itimerval{
         struct timeval it_interval; /* next value */
            struct timeval it_value;    /* current value */
    };
    struct timeval{
         long tv_sec;                /* seconds */
            long tv_usec;               /* microseconds */
    
    };
    秒     微秒
    1秒=1000毫秒
    1毫秒=1000微秒
    
    举例说明   编写代码实现定时器,起始时间是进程启动3秒,然后每隔0.5秒发送一个SIGALRM信号。
    代码参见   timer.c
    
    信号结束了
    
    六、system v  IPC
     消息队列   共享内存     信号量集
     
    在内核管理的内存,用于进程间通讯的内存,称为system v ipc object
    操作系统需要管理这些对象。
    如何查看当前系统里有哪些对象?
    ipcs
    
    在操作系统中这些对象,每一个都有自己的id。便于操作系统的管理。
    在用户态需要获取这些对象的id。
    获取这些对象的id。需要在用户态有一个键值(唯一的)
    将键值和id绑定,这样就可以获取到对象的id。
    
    如何获取这个键值?
    ftok(3)
    #include <sys/types.h>
    #include <sys/ipc.h>
    key_t ftok(const char *pathname, int proj_id);
    功能:获取system v ipc的一个键值  key
    参数:
    pathname:指定一个文件名,这个文件是存在的,可访问的
    proj_id:必须是非0.取这个数的有效低8位。
    返回值:
    -1  错误  errno被设置
    返回一个key值。
    
    举例说明  使用ftok(3)获取一个键值
    代码参见ftok.c
    
    消息队列
    从系统中获取一个消息队列。如果系统里没有,创建消息队列,将这个消息队列的id给我返回。如果有这个消息队列,返回id即可。
    
    msgget(2)
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    int msgget(key_t key, int msgflg);
    功能:获取一个消息队列的id
    参数:
    key:ftok(3)的返回值
    msgflg:
    IPC_CREAT:如果不存在创建,存在,不创建
     IPC_EXCL:如果和IPC_CREAT一起指定,存在的时候,报错。
    mode:指定了消息队列的权限
    返回值:
    -1   错误  errno被设置
    返回消息队列的id
    
    举例说明  使用msgget(2)从内核获取消息队列
    代码参见msgget.c
    
    向消息队列中发送消息和从消息队列获取消息
    msgsnd(2)
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/msg.h>
    int msgsnd(int msqid, const void *msgp, 
            size_t msgsz, int msgflg);
    功能:向消息队列发送消息
    参数:
    msqid:指定了存放消息的消息队列的id。
    msgp:指向了消息的地址
    msgsz:指定了消息内容的长度
    msgflg:
    IPC_NOWAIT:非阻塞
    0   阻塞
    返回值:
    成功   0
    -1  失败   errno被设置
    
    将一份拷贝追加到消息队列中
    
    
    ssize_t msgrcv(int msqid, void *msgp,
         size_t msgsz, long msgtyp,int msgflg);
    功能:从消息队列接收消息
    参数:
    msqid:指定了消息队列的id
    msgp:指向了消息的地址
    msgsz:指定了消息内容的长度
    msgtyp:指定了消息的类型
    msgflg:
    IPC_NOWAIT:没有消息的时候,立即返回错误   errno被设置
    0    没有消息的时候,阻塞等待
    
    返回值:
    -1  失败   errno被设置
    成功  返回实际拷贝到mtext中的字节数。
    
    
    需要用户自定义这个类型
    struct msgbuf {
            long mtype;       /* message type, must be > 0 */
            char mtext[1];    /* message data */
    };
    typedef struct msgbuf msgb_t;
    msgb_t *st=malloc(sizeof(msgb_t)+strlen(mtext)-3);
    st->mtext
    
    举例说明    两个进程通过消息队列实现进程间的通讯。
    代码参见   send.c   recv.c
    
    总结:
    一、pause(2)函数的使用
    二、信号从产生到处理的整个过程
    三、可重入函数
    四、作业  前台作业和后台作业
    五、使用setitimer(2)实现定时器
    六、进程间通讯    system v ipc
    消息队列
  • 相关阅读:
    深入理解JavaScript闭包
    冒泡排序
    Objective-C中的self和super
    IOS中UIKit——UIButton的背景图像无法正常显示的原因
    IOS绘图——简单三角形
    NSDateFormatter中时间格式串的含义
    IOS屏幕布局
    IOS学习感想
    WWDC————苹果全球开发者大会
    刚开始学IOS遇到的类和方法
  • 原文地址:https://www.cnblogs.com/Kernel001/p/7732629.html
Copyright © 2020-2023  润新知