Ubuntu下UnixC的第九天

回忆上次课程
一、waitpid(2)
回收进程资源   可以指定要等待的进程
可以非阻塞
进程组的概念
wait(2)
二、进程映像的替换
execve(2)  使用新的进程映像替换掉旧的映像
代码段  数据段  栈段  堆
遗言函数  atexit(3)
     execl(3)家族的函数    
int main(int argc,char* argv[],char* envp[]);
bash->fork->exec("a.out")->wait();
bash  内部命令  外部命令
exec跟环境变量的结合

默认的情况下,子进程继承父进程的环境变量  可以给子进程传递一个环境变量列表,替换掉从父进程继承的环境变量

三、环境变量
使用库函数访问环境变量
getenv(3)  setenv(3)  unsetenv(3) clearenv(3)
四、管道
无名管道      在内存里开辟了地址,有文件描述符的名字,没有文件的名字    
        文件的原理   单向的    具有亲缘关系的进程间通讯  
        read(2)、write(2)  会阻塞
        pipe(2)创建管道
有名管道    

今天的内容:
一、有名管道的使用
 管道类型的文件
    p
    这种类型的文件,没有内容。
    也就是说内容为0,这种类型的文件只是起到进程间通讯的桥梁作用,只是一个接口而已
    使用有名管道进行进程间的通讯,可以用于任意进程
    创建有名管道类型的文件(管道类型)
mkfifo(3)
     #include <sys/types.h>
       #include <sys/stat.h>

       int mkfifo(const char *pathname, mode_t mode);

    功能:创建一个管道类型的文件
    参数:
    pathname指定管道文件的文件名   
    mode 指定新创建的管道文件的权限
    mode &~mask
    返回值:成功0   失败-1  errno被设置

使用有名管道实现进程间的通讯
1 编写程序,创建管道类型文件 pa.c
2 编写程序  从管道文件里读取文件  pb.c
3 编写程序,向管道里写入数据    pc.c
进程暂告段落
bsd system v ipc
消息队列    
共享内存
信号量集
二、信号的基础
什么是信号?  信号就是软终端     软件实现中断机制

中断   中断处理程序
信号是发送给进程   目标
进程收到信号以后,会对信号做出处理   信号的处理函数
信号处理函数  进程  异步的
系统为用户提供的信号
kill -l
信号编号  信号的名字
kill -信号编号 pid

信号产生  信号接收  信号的处理
不确定的 就是未决
信号的未决状态   未决信号


三、给进程注册信号处理函数
进程默认的从父进程继承信号处理函数
bash   a.out
bash采用的是默认信号处理函数
进程对信号的处理
默认   SIG_DFL
忽略    SIG_IGN
用户自定义    user_define

默认的处理方式,基本上都是终止当前进程
如何改变进程对信号的处理函数?
向进程注册信号处理函数

signal(2)
      #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);
    功能:改变进程对信号的处理函数
    参数:
        signum指定了信号的编号
        handler指定了信号的处理函数
            默认   SIG_DFL
            忽略    SIG_IGN
            用户自定义    user_define
    返回值:
        错误 SIG_ERR  errno被设置
        成功  返回改变前的信号处理函数的值

 typedef void (*sighandler_t)(int);

sighandler_t   类型 是*类型的别名,访问规则用函数的访问规则


    int arr[3];
    int func(int ,int);
    {
    ...
    ...
    }
举例说明  信号处理
first.c

子进程继承父进程的信号处理函数
second.c
四、信号的产生
有三种那个方法
1 硬件产生信号   ctrl+c ctrl+\
2 使用命令给进程发送信号  kill -编号 pid
3 使用库函数或者系统调用给进程发送信号 
kill(2) 
      #include <sys/types.h>
       #include <signal.h>

       int kill(pid_t pid, int sig);
    功能:给一个进程(组)发送信号
    参数:pid >0   给指定进程发送信号
        sig指定了信号
    返回值:成功0   错误-1  errno被设置
    
    写一个t_kill 信号编号 pid
 
raise(3)
      #include <signal.h>

       int raise(int sig);

DESCRIPTION
       The raise() function sends a signal to the calling process or
       thread.  In a single-threaded program it is equivalent to 
    kill(getpid(), sig);

       In a multithreaded program it is equivalent to pthread_kill(pthread_self(), sig);

       If the signal causes a handler to  be  called,  raise()  will
       return only after the signal handler has returned.
    返回值:成功返回0,失败返回非0


重点alarm(2)、
       #include <unistd.h>

       unsigned int alarm(unsigned int seconds);

    功能:设置一个用于信号传达的闹钟
    参数:
    seconds指定时间,在这个时间内将SIGALRM递达给当前进程
    如果是0,所有未决的闹钟(原来设置的,目前还未执行的)都被取消,返回剩下的秒数
        
    如果在seconds秒内设置了新的闹钟,之前的闹钟会被覆盖
    
    返回值:0  没有原来调度的闹钟
        非0   原来设定的闹钟还剩下的秒数(离执行还剩的时间)
    
    使用alarm(2)设置闹钟
    代码参见  alarm.c
    
补充:pause(2)
     #include <unistd.h>

       int pause(void);
    功能:等待信号(当前进程或者线程休眠直到接收到终止信号或者信号捕获函数的调用)
    参数:
    返回值:错误 -1  errno被设置  只有捕获到信号,信号处理函数被调用之后才返回

    使用alarm(2)和pause(2)实现sleep(3)的功能
    代码参见 t_sleep.c
    unsigned int sleep(unsigned int seconds);
    
五、信号的阻塞
struct node{
    int data;
    struct node *next;
}
typedef struct node node_t;

int queue_t[5];
typedef int queue_t[5];
queue_t q;
向队列插入数据
从队列删除数据
队列的初始化
队列的销毁

sigset_t 类型  信号集类型
相关的操作
sigemptyset(3)
  #include <signal.h>

   int sigemptyset(sigset_t *set);
    功能:将信号集初始化为空。不包含任何信号
    参数:
    set 要初始化的信号集
    返回值:成功返回0   错误返回-1  errno被设置
    
   int sigfillset(sigset_t *set);
    功能:初始化信号集为满。包含所有的信号
    参数:
    set指定要初始化的信号集
    返回值:成功返回0   错误返回-1  errno被设置
   int sigaddset(sigset_t *set, int signum);
    功能:将信号添加到信号集
    参数:
    set指定信号集
    signum指定信号
    返回值:成功返回0   错误返回-1  errno被设置
       int sigdelset(sigset_t *set, int signum);
    功能:从信号集删除指定的信号
    参数:
    set指定信号集
    signum 指定信号
    返回值:成功返回0   错误返回-1  errno被设置
       int sigismember(const sigset_t *set, int signum);
    功能:测试信号是否属于信号集
    参数:
    set    指定信号集
    signum 指定要测试的信号
    返回值:如果signum是set成员  返回1
        如果不是其成员  返回0
        错误返回 -1  errno被设置

举例说明 初始化一个信号集  将2 3 6 信号添加到集合中。
    测试3号信号是不是信号集中的一员
    然后从信号集中删除三号信号,再次测试3号是不是信号集一员
    代码参见 sigset.c

 

alarm.c

#include<stdio.h>
#include<unistd.h>
int main(){
    //设置闹钟
    alarm(5);
#if 0
    for(int i=1;i<280000;i++)
            printf("i=%d\n",i);
#endif
    sleep(2);
//    int n=alarm(0);//取消未决的闹钟
//    printf("n==%d\n",n);
    int n=alarm(1);
        printf("n==%d\n",n);
    for(int j=1;j>0;j++)
    {    printf("j=%d\n",j);
    }
    return 0;
}
 

first.c

#include<signal.h>
#include<t_stdio.h>
#include<unistd.h>
#include<stdlib.h>
//用户自定义信号处理函数
void handle(int n){
    printf("n is %d\n",n);//信号的编号
    exit(0); 
}

int main(void){
    signal(2,SIG_IGN);
    signal(3,handle);
    signal(9,SIG_IGN);
    signal(SIGALRM,handle);
    alarm(2);

    while(1);
    return 0;
}
 

pa.c

#include<t_stdio.h>
#include<t_file.h>
#include<sys/stat.h>
int main(int argc,char* argv[]){
    //创建管道类型文件
    //文件名通过argv[1]传递
    int ff=mkfifo(argv[1],0644);
    if(ff==-1) E_MSG("mkfifo",-1);
    printf("mkfifo创建成功..\n");
    return 0;
}
 

pb.c

#include<t_stdio.h>
#include<t_file.h>

int main(int argc,char* argv[]){
    
    char buf[128];
    //打开文件,只读
    int fd=open(argv[1],O_RDONLY);
    if(fd==-1) E_MSG("open",-1);    
    int r=read(fd,buf,128);

    //读取数据,显示到显示器
    printf("读出内容:\n");
    write(1,buf,r);
    
    
    //关闭文件描述符
    close(fd);
    return 0;
}
 

pc.c

#include<t_stdio.h>
#include<t_file.h>
#include<string.h>
int main(int argc,char* argv[]){
    
    char* msg="this is a pipe test..\n";
    //打开文件,只读
    int fd=open(argv[1],O_WRONLY);
    if(fd==-1) E_MSG("open",-1);    
    //写入数据,如果没有进程读取,阻塞
    
        write(fd,msg,strlen(msg));
        
    //关闭文件描述符
    close(fd);
    return 0;
}
 

second.c

#include<signal.h>
#include<t_stdio.h>
#include<t_file.h>
//用户自定义信号处理函数
void handle(int n){
    printf("n is %d\n",n);//信号的编号
    return; 
}

int main(void){
    //向进程注册信号处理函数
    signal(9,SIG_IGN);
    signal(3,handle);
    signal(2,SIG_IGN);
    //创建子进程
    pid_t pid=fork();
    while(1);
    return 0;
}
 

sigset.c

#include<signal.h>
#include<stdio.h>
#include<unistd.h>

int main(){
    sigset_t set;
    //初始化信号集为空
    sigemptyset(&set);
    //将 2 3 6添加到set集合中
    sigaddset(&set,2);
    sigaddset(&set,3);
    sigaddset(&set,6);
    //测试3号信号是不是set的一员
    int is=sigismember(&set,3);
    printf("before delete...\n");
    if(is==1) printf("yes...\n");
    else printf("no...\n");
    //将3号从set删除
    sigdelset(&set,3);
     is=sigismember(&set,3);
     printf("after delete\n");
    if(is==1) printf("3yes...\n");
    else printf("3no...\n");

    return 0;
}
 

t_kill.c

#include<t_stdio.h>
#include<signal.h>
#include<t_file.h>
#include<stdlib.h>
int main(int argc,char* argv[]){
    
    int a=kill(atoi(argv[2]),atoi(argv[1]));
    if(a==-1) E_MSG("kill",-1);
    return 0;
}
//给当前进程发送信号
//kill(getpid(),signum);
//raise(signum)==kill(getpid(),signum);
 

t_sleep.c

#include<t_stdio.h>
#include<unistd.h>
#include<signal.h>
//信号处理函数
void handle(int n){
    printf("%d\n",n);
}
unsigned int t_sleep(unsigned int seconds){
    signal(SIGALRM,handle);
    printf("%d",SIGALRM);
    alarm(seconds);//设置闹钟
    pause();//暂停,等待信号
    return alarm(0);
}
int main(){

    while(1){
    t_sleep(1);
    printf("hehehehe...\n");
    }

    return 0;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值