zoukankan      html  css  js  c++  java
  • linux高级编程day06 笔记

    问题解答:
      1.exit(状态码)返回状态码有什么意义?
       返回值被系统得到.系统根据状态码进行日志记录.
       返回值被调用者得到:system/wait.程序会根据返回状态码进行对应处理。
       exit(状态码)=main函数中的return 状态码; 
      2.状态码的第二个字节才是exit()的返回值或者return值。

    一.进程的基本控制
     1.进程的常见控制函数
       1.1.为什么需要控制进程?
       1.2.pause/sleep/usleep
       1.3.atexit  on_exit 

    View Code
    #include <stdio.h>
    #include <stdlib.h> 
    void fun()
    {
        printf("over\n");
    }
    main()
    {
        atexit(fun); //注册终止函数(即main执行结束后调用的函数) 
        printf("Process!\n");
    }

     2.进程与文件锁
       在多进程下文件读写是共享的
       问题:
         怎么知道一个文件正在被另外进程读写?
       解决方案:
         文件锁。(建议锁)
       API:
         fcntl(文件锁受内核参数影响)  
       编程技巧:
         对文件加锁
         判定一个文件是否存在锁
       函数说明:
         int fcntl(
           int fd,//被加锁的文件描述符号
           int cmd,//锁的操作方式:F_SETLK(已经加锁,异常返回) F_UNLK F_SETLKW(已经加锁,则阻塞等待)
           struct flock *lk);//锁的描述
         
         返回值:
           0:加锁成功
           -1:加锁失败

    View Code
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    main()
    {
        int fd;
        struct flock lk;
        int r;
        //打开一个文件
        fd=open("a.txt",O_RDWR);
        if(fd==-1) printf(":%m\n"),exit(-1);
        //描述锁
        lk.l_type=F_WRLCK;
        lk.l_whence=SEEK_SET;
        lk.l_start=5;
        lk.l_len=10;
        //加锁
        r=fcntl(fd,F_SETLK,&lk);
        if(r==0) printf("加锁成功!\n");
        else    printf("加锁失败!\n");
        while(1);    
    }    

    案例:
       写两个程序:
          A:加锁
          B:获取锁的信息

    View Code
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    main()
    {
        int fd;
        struct flock lk;
        int r;
        //打开一个文件
        fd=open("a.txt",O_RDWR);
        if(fd==-1) printf(":%m\n"),exit(-1);
        //描述锁
        lk.l_type=F_WRLCK;
        lk.l_whence=SEEK_SET;
        lk.l_start=5;
        lk.l_len=3;
        //加锁
        r=fcntl(fd,F_SETLK,&lk);
        if(r==0) printf("加锁成功!\n");
        else    printf("加锁失败!\n");
        while(1);    
    }
    View Code
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <fcntl.h>
    
    main()
    {
        int fd;
        struct flock lk={0};
        int r;
        
        fd=open("a.txt",O_RDWR);
        if(fd==-1) printf("::%m\n"),exit(-1);
        
        r=fcntl(fd,F_GETLK,&lk);
        if(r==0) 
            printf("得到锁成功!\n");
        if(lk.l_type==F_WRLCK)
        {
            printf("写锁!\n");
        }
        printf("start:%d,len:%d\n",lk.l_start,lk.l_len);
        
        printf("PID:%d\n",lk.l_pid);
        
    }

    锁也是一个进程可以共享的信息。
       
    二.信号
     1.信号的作用
       背景:
         进程之间通信比较麻烦。
         但进程之间有必须通信,比如父子进程之间。
       作用:
         通知其他进程响应。进程之间通信机制.
         信号:
          接受信号的进程马上停止.调用信号处理函数.
         信号处理函数:
          默认处理函数.
            打印信号信息,退出进程.
          用户处理函数.       
       中断:
         软中断.
         
    案例:
      1.进程之中,默认信号处理
      2.进程之中,用户信号处理

    View Code
    #include <unistd.h>
    #include <stdio.h>
    #include <signal.h>
    void handle(int s)
    {
        printf("我是信号发生!\n");    
    }
    
    main()
    {
        //signal(SIGWINCH,handle);
        signal(35,handle);
        while(1)
        {
            //printf("进程在执行:%d!\n",getpid());
            //sleep(1);
        }
    }

      3.中断
      
      kill -s 信号  进程ID
      kill -信号  进程ID     
      信号:数字1-31  34-64
         宏SIGINT=2
      ctrl+d 发送信号2 SIGINT
      kill -l察看所有信号    
      
      信号SIGKILL SIGSTOP不能被处理.
      
      
    案例:
      发送信号
      int kill(pid_t pid,int s)
      进程ID:
        >0:发送信号到指定进程
        =0:发送信号到该进程所在进程组的所有进程
        -1:发送给所有进程,除init外
        <0:发送给指定的进程组(组ID=绝对值)

    View Code
    #include <stdio.h>
    #include <signal.h>
    main()
    {
        int i;
        //while(1)
        for(i=0;i<5;i++)
        {
            kill(4601,35);
            
        }
    }

     2.信号发送与安装
       signal
       kill
     3.信号的应用
       3.1.延时器timeout
         SIGALRM
         信号发出函数:alarm
       3.2.定时器

    int setitimer(int which,//计时方式
                            //ITIMER_REAL  / ITIMER_VIRTUAL /ITIMER_PROF
                const struct itimerval *val,//定时器的时间参数
                struct itimer *oldval);//返回原来设置的定时器
                                                //如果=NULL,则不返回
    struct itimerval
    {
            struct timeval it_interval;//间隔时间
            struct timeval it_value;//延时时间
    }
    struct timeval
    {
         long tv_sec;
         long tv_usec;
    }
    View Code
    #include <stdio.h>
    #include <signal.h>
    #include <sys/time.h>
    void deal(int s)
    {
        printf("起床!\n");
        
    }
    main()
    {
        struct itimerval v={0};
        
        signal(SIGALRM,deal);
        
        //v.it_value.tv_sec=3; //程序启动3秒后触发,可以不设定tv_usec
        v.it_value.tv_sec=0;
        v.it_value.tv_usec=1;  //让程序一启动就触发。不能设为0
        v.it_interval.tv_sec=1; //间隔1秒
        //alarm(5);
        setitimer(ITIMER_REAL,&v,0);
        while(1)
        {
            //.....
        }
    }

       信号应用:
         系统与应用程序之间
         应用于应用程序之间
         父子进程之间
      案例1:
         使用定时器信号,实现多任务.
         实现:
           实现7位随机数
           使用中断实现时间的显示

    View Code
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <math.h>
    #include <curses.h>
    WINDOW *w;
    int num;
    int isstop=0;
    void handle(int s)
    {
        if(s==SIGUSR1)
        {
            if(isstop==1)
                isstop=0;
            else
                isstop=1;
        }
    }
    
    main()
    {
        initscr();
        curs_set(0);//隐藏光标
        noecho();//禁止输入回显
        //keypad(stdscr,TRUE);
        //keypad(w,TRUE);
        //创建子窗体
        w=derwin(stdscr,3,11,(LINES-3)/2,(COLS-11)/2);
        box(w,0,0);//给子窗体加边框
        refresh();
        wrefresh(w);
        if(fork())
        {
            //显示7位数的随机数
            signal(SIGUSR1,handle);
            while(1){
                if(isstop==1)
                {
                    pause();//pause会被信号中断停止 ***
                }
                num=rand()%10000000;//产生7位随机数
                mvwprintw(w,1,2,"%07d",num);//显示随机数
                refresh();//刷新屏幕。
                wrefresh(w);
                usleep(10000);//暂停10毫秒
            }
        }
        else
        {
            //处理按键
            while(1)
            {
                getch();
                //if(ch==KEY_ENTER)
                {
                    kill(getppid(),SIGUSR1);
                }
            }
        }
        
        endwin();
    }

      案例2:
         实现父子进程之间通信
         
         控制进程.
              
       sleep与pause函数被信号影响后,sleep不再继续sleep.
       pause不再pause.
    练习:
       1.在curses显示7位随机数     
       
       其他信号函数
         raise
       
     4.信号的可靠与不可靠以及信号的含义
       信号有丢失.(信号压缩)
       由于历史的缘故:信号有压缩的需求.
       可靠信号(实时信号)与不可靠信号(非实时信号).
       
       早期信号 1-31 31个信号, 不可靠(与系统有关).
       后期信号34-64 31个信号,可靠信号(用户信号)  
     
     5.信号的操作
       信号导致的问题
       1.信号屏蔽 

    int sigprocmask(int how,//操作方式
                    SIG_BLOCK
                    SIG_UNBLOCK
                    SIG_SETMASK
        const sigset_t *sigs,//操作的信号集合
        sigset_t *oldsigs);//返回原来操作的信号集合

         1.声明信号集合
           sigset_t  sigs;
          2.加入屏蔽信号
            一组信号集合维护函数:
            2.1. 清空集合sigemptyset
            2.2. 添加信号到集合sigaddset
            2.3. 从集合删除信号sigdelset
            2.4. 添加所有信号到集合sigfillset
            2.5. 判定信号是否在集合sigismember
         3.屏蔽信号
         4.接触屏蔽 
          
       2.信号屏蔽的切换
         int sigsuspend(sigset_t *sigs);
         屏蔽新的信号,原来的信号失效.
         sigsuspend是阻塞函数.对参数信号屏蔽.
         对参数没有指定的信号不屏蔽,但当没有屏蔽信号处理函数调用完毕
         sigsuspend返回条件:
            1.信号发生,并且信号是非屏蔽信号
            2.信号必须要处理,而且处理函数返回后,sigsuspend才返回.
         
         sigsuspend设置新的屏蔽信号,保存旧的屏蔽信号
         而且当sigsuspend返回的时候,恢复旧的屏蔽信号.

    View Code
    #include <stdio.h>
    #include <signal.h>
    void h(int s)
    {
        printf("非屏蔽信号发生!\n");
    }
    main()
    {
        sigset_t sigs;
        
        signal(SIGWINCH,h);
        
        sigemptyset(&sigs);
        sigaddset(&sigs,2);
        printf("屏蔽开始!\n");
        sigsuspend(&sigs);
        printf("屏蔽结束!\n");
        
    }    

       3.查询被屏蔽的信号
         int sigpending(sigset_t *sets);

    View Code
    #include <stdio.h>
    #include <signal.h>
    void h(int s)
    {
        printf("抽空处理int信号\n");
    }
    main()
    {
        int sum=0;
        int i;
        //1.
        signal(SIGINT,h);
        sigset_t sigs,sigp,sigq;
        //2.
        sigemptyset(&sigs);
        sigemptyset(&sigp);
        sigemptyset(&sigq);
        
        sigaddset(&sigs,SIGINT);
        //3.
        sigprocmask(SIG_BLOCK,&sigs,0);
        for(i=1;i<=10;i++)
        {
            sum+=i;
            sigpending(&sigp);
            if(sigismember(&sigp,SIGINT))
            {
                printf("SIGINT在排队!\n");
                sigsuspend(&sigq);
                //使原来屏蔽信号无效,开放原来信号
                //使新的信号屏蔽,
                //当某个信号处理函数处理完毕
                //sigsuspend恢复原来屏蔽信号,返回 
            }
            sleep(1);
        }
        printf("sum=%d\n",sum);
        sigprocmask(SIG_UNBLOCK,&sigs,0);
        printf("Over!\n");
    }

    回顾:
      1.进程控制sleep pause
      2.理解信号的中断流程
      3.发射信号(Shell/code),处理信号
      4.alarm与setitimer
      5.信号应用:实现简单多任务与进程之间通信
      6.使用信号+sleep/pause控制进程
      7.信号的屏蔽
      8.了解sigpending与 sigsuspend的使用.

    作业:
      
      1.写一个程序,创建两个子进程,分别计算1-5000与5001-1000素数,
         通过信号让,父进程专门完成数据保存.
      
      2.完成课堂上的作业:
         显示7位随机数,同时使用定时器信号显示时间
         在使用键盘控制7位随机数的停止与继续显示.
         (建议美化) 
      3.完成如下作业:
         在屏幕水平同时显示移动两个字符.
      
    思考:
      信号处理函数调用过程中,是否被其他信号影响.        
       
    明天:
     1.信号与进程间数据传递
       sigqueue=kill与sigaction=signal
     2.IPC:
       基于文件
         无序文件:映射
         有序文件:管道文件:有名/匿名
              socket文件
       基于内存
         无序内存
            内存共享
         有序内存  
            共享队列

  • 相关阅读:
    web页面接入QQ客服的方法
    如何使用webapi集成swagger
    TCP的三次握手和四次挥手
    笔记-ASP.NET WebApi
    .net开发人员应该知道的几个网站
    HttpClient在async中产生的代码不执行和堵塞
    【转】CA证书申请+IIS配置HTTPS+默认访问https路径
    WebApi捕捉异常的一套方案
    使用Topshelf部署你的Job
    使用ajax局部更新Razor页面
  • 原文地址:https://www.cnblogs.com/tangzhengyue/p/2650194.html
Copyright © 2011-2022 走看看