c++ 学习笔记(高级linux编程) day6

本笔记详细介绍了Linux高级编程中的进程控制、文件锁、信号等核心概念及其实现方式,包括进程的常见控制函数、文件锁的使用、信号的作用与处理方法,以及如何通过信号实现进程间的通信和控制。

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 

#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:加锁失败

#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:获取锁的信息

#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);   

}

#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.进程之中,用户信号处理

#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=绝对值)

#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;

}

#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位随机数
       使用中断实现时间的显示

#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返回的时候,恢复旧的屏蔽信号.

#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);

#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文件
   基于内存
     无序内存
        内存共享
     有序内存  
        共享队列

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值