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

 

转载于:https://www.cnblogs.com/tangzhengyue/archive/2012/08/22/2650194.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值