信号之后续实验部分(二)

原创 2018年02月07日 20:37:42

实验一

题目:wait系列函数和SIGCHILD的关系?

  首先避免造轮子搜集下资料:CSDN博友
  以上博友的分析有其不准确的地方,做一点补充:wait的实现,不依赖SIGCHILD,而system函数的实现内部使用wait系列函数,如果在system之外有设置SIGCHILD的捕获函数,则需要在system函数中屏蔽该信号。
  以下代码取自stackoverflow

void my_sigchld_handler(int sig)
{
    pid_t p;
    int status;

    while ((p=waitpid(-1, &status, WNOHANG)) != -1)
    {
       /* Handle the death of pid p */
    }
}
struct sigaction sa;

memset(&sa, 0, sizeof(sa));
sa.sa_handler = my_sigchld_handler;

sigaction(SIGCHLD, &sa, NULL);

分析以上程序的优点:

  • 避免僵死进程,这点while循环的时候就使所有的僵尸进程拜拜。
  • 实现了主进程不会无限制等待子进程的结束信息,注意wait放在signal handler和放在main中所带来的影响不同。
  • 对于SIGCHLD信号,如果多个子进程同时,或者间隔很短的时间结束,那么while loop恰恰能很好的处理这种情况。
  • 使用WNOHANG,从而如果处理完所有结束的子进程时,或者遇到子进程还是正在运行时,不会永远block在这里。

实验二

题目:The process creates a file and writes the integer 0 to the file. The process then calls fork, and the parent and child alternate incrementing the counter in the file. Each time the counter is incremented, print which process (parent or child) is doing the increment.

  下面是我的一种实现方式,使用了sigsuspend的特性,并且取巧的让父进程来最终结束整个程序,否则还要考虑如何防止父进程suspend forever如果多个程序,包括后面的多线程访问一个文件的话,一定要慎重offset的位置,否则会发生意想不到的结果。

#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
#include<signal.h>
#include<unistd.h>
#include<err.h>
#include <sys/types.h>

void sig_usr(int signo)
{
}


int main(int argc,char **argv)
{
        pid_t pid;
        int fd;
        sigset_t newmask,oldmask;
        unsigned char number=0;
        if (signal(SIGUSR1, sig_usr) == SIG_ERR)
                errx(1,"signal(SIGUSR1) error");
        if (signal(SIGUSR2, sig_usr) == SIG_ERR)
                errx(1,"signal(SIGUSR2) error");
        sigemptyset(&newmask);
        sigaddset(&newmask, SIGUSR1);
        sigaddset(&newmask, SIGUSR2);
        if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
                errx(1,"SIG_BLOCK error");
        if((fd=open("state.txt",O_RDWR|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0)
                errx(1,"error in creating a file\n");
        else
        {
                if(write(fd,&number,1)< 0)
                        errx(1,"error in writing this file\n");
        }
        lseek(fd,0,SEEK_SET);
        if((pid=fork())<0)
                errx(1,"fork error\n");
        if(pid>0)
        {
                unsigned char temp;
                for(;;)
                {
                        sigsuspend(&oldmask);
                        lseek(fd,0,SEEK_SET);
                        if(read(fd,&temp,1) == -1 )
                        {
                                errx(1,"parent:error in reading a file\n");
                        }
                        else
                        {
                                lseek(fd,0,SEEK_SET);
                                if(++temp>200)
                                {
                                    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
                                        errx(1,"SIG_SETMASK error");
                                    errx(1,"parent: the number is too lager now\n");
                                }
                                if(write(fd,&temp,1) == -1)
                                        errx(1,"parent:error in writing a number to this file\n");
                                else
                                        printf("This number is incremented by the parent.It's value is:%d\n",temp);
                        }
                        kill(pid,SIGUSR2);
                }
         }
         else
         {
                unsigned char temp;                                                                                                                                                                                    
                for(;;)                                                                                                                                                                                                
                {                                                                                                                                                                                                      
                        kill(getppid(),SIGUSR1);                                                                                                                                                                       
                        sigsuspend(&oldmask);                                                                                                                                                                          
                        lseek(fd,0,SEEK_SET);                                                                                                                                                                          
                        if(read(fd,&temp,1) == -1)                                                                                                                                                                     
                        {                                                                                                                                                                                              
                                errx(1,"child:error in reading a file\n");                                                                                                                                             
                        }                                                                                                                                                                                              
                        else                                                                                                                                                                                           
                        {                                                                                                                                                                                              
                                lseek(fd,0,SEEK_SET);                                                                                                                                                                  
                                if(++temp>200)                                                                                                                                                                         
                                {                                                                                                                                                                                      
                                        if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)                                                                                                                              
                                                errx(1,"SIG_SETMASK error");                                                                                                                                           
                                        errx(1,"child: the number is too lager now\n");                                                                                                                                
                                }                                                                                                                                                                                      
                                if(write(fd,&temp,1) == -1)                                                                                                                                                            
                                        errx(1,"child:error in writing a number to this file\n");                                                                                                                      
                                else                                                                                                                                                                                   
                                        printf("This number is incremented by the child.It's value is:%d\n",temp);                                                                                                     
                        }                                                                                                                                                                                              
                }                                                                                                                                                                                                      
         }                                                                                                                                                                                                             
}      

  看看结果:

[root@localhost ~]# ./10_1
This number is incremented by the parent.It's value is:1
This number is incremented by the child.It's value is:2
This number is incremented by the parent.It's value is:3
This number is incremented by the child.It's value is:4
......
This number is incremented by the parent.It's value is:197
This number is incremented by the child.It's value is:198
This number is incremented by the parent.It's value is:199
This number is incremented by the child.It's value is:200
10_1: parent: the number is too lager now
  • 每次读和写都会使offset位置加1。
  • 经过fork的后的进程共享fork之前打开的文件描述符,此时每个进程单独具有一个内核维护的打开文件列表。
  • 上述程序使用pwritepread能够更加简洁方便。

实验三

题目:Write a program that calls fwrite with a large buffer (about one gigabyte). Before calling fwrite, call alarm to schedule a signal in 1 second. In your signal handler, print that the signal was caught and return. Does the call to fwrite complete? What’s happening?

  该实验比较简单,很快就可以验证

#include<stdlib.h>
#include<stdio.h>
#include<fcntl.h>
#include<signal.h>
#include<string.h>
#include<unistd.h>
#include<err.h>
#define  MAX  1073741824

void sig_alrm(int signo)
{
          printf("the signal we got is:%d\n",signo);
}


int main(int argc,char **argv)
{
          pid_t pid;
          FILE * fp;
          char * buffer;
          if((buffer=malloc(MAX)) == NULL)
          {
                  errx(1,"error calling the malloc\n");
          }
          memset(buffer,'1',MAX);
          if (signal(SIGALRM, sig_alrm) == SIG_ERR)
                  errx(1,"signal(SIGUSR1) error");
          if((fp=fopen("state.txt","w+")) == NULL)
                  errx(1,"error in creating a file\n");
          else
          {
                  alarm(1);
                  if(fwrite(buffer,sizeof(char),MAX,fp)<MAX)
                        errx(1,"error in writing this file\n");
                  else
                        printf("fwirte complete!\n");
                  alarm(0);
          }
}

  观察结果:

[root@localhost ~]# ./10_2
the signal we got is:14
fwirte complete!
[root@localhost ~]# 

  可以看到和预期的一样,对于linux来说,如同signal篇所述:某些系统调用虽然被中断,但是依然会默认重新开始,所以最后还是完成了fwrite

实验四

题目:Modify Figure 3.5 as follows: (a) change BUFFSIZE to 100; (b) catch the SIGXFSZ signal using the signal_intr function, printing a message when it’s caught, and returning from the signal handler; and (c) print the return value from write if the requested number of bytes wasn’t written. Modify the soft RLIMIT_FSIZE resource limit (Section 7.11) to 1,024 bytes and run your new program, copying a file that is larger than 1,024 bytes. (Try to set the soft resource limit from your shell. If you can’t do this from your shell, call setrlimit directly from the program.)

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/resource.h>
#include <unistd.h>
#include <err.h>
#define BUFFSIZE 100
#define MAX 1024
typedef void Sigfunc(int);
Sigfunc * signal_intr(int signo, Sigfunc *func)
{
        struct sigaction act, oact;
        act.sa_handler = func;
        sigemptyset(&act.sa_mask);
        act.sa_flags = 0;
        act.sa_flags |= SA_INTERRUPT;
        if (sigaction(signo, &act, &oact)<0)
                return(SIG_ERR);
        return(oact.sa_handler);
}
void sig_fsz(int signo)
{
        fprintf(stderr,"the signal we got is:%d\n",signo);
}
int main(void)
{
        int n,m;
        char buf[BUFFSIZE];
        struct rlimit new={MAX,MAX};
        if(setrlimit(RLIMIT_FSIZE, &new)== -1)
                errx(1,"error in setting limit\n");
        if(getrlimit(RLIMIT_FSIZE,&new)== -1)
                errx(1,"error in getting limit\n");
        else
                fprintf(stderr,"limit is :%d\n",new.rlim_cur);
        if (signal_intr(SIGXFSZ, sig_fsz) == SIG_ERR)
                errx(1,"signal(SIGUSR1) error");
        while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
        {
                fprintf(stderr,"read number:%d\n",n);
                if ((m= write(STDOUT_FILENO, buf, n)) != n)
                {
                        if(m == -1)
                                errx(1,"error in writing");
                        else
                                fprintf(stderr,"write number:%d\n",m);

                }
        }                                                                                                                                         
        if (n < 0)                                                                                                                                
                errx(1,"read error");                                                                                                             
        exit(0);                                                                                                                                  
}     

  接着,看看运行结果:

[root@localhost ~]# ls -alh fileio.c
-rw-r--r--. 1 root root 1.3K Nov  3 10:00 fileio.c         
[root@localhost ~]# ./10_3 < ./fileio.c > newfile
limit is :1024
read number:100
read number:100
read number:100
read number:100
read number:100
read number:100
read number:100
read number:100
read number:100
read number:100
read number:100
write number:24
read number:100
the signal we got is:25
10_3: error in writing

  总共读了12次100个字节,但是第11次的时候,只写入了24个字节,然后第12次读取100个字节,当其再打算写入时触发SIGXFSZ信号,进入信号处理函数,从信号处理函数返回以后write中断,返回错误信息,终止程序。

版权声明:本文为博主原创文章,未经博主允许不得转载。

数据结构实验之排序二:交换排序

数据结构实验之排序二:交换排序 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 冒泡...
  • guoqingshuang
  • guoqingshuang
  • 2015年12月20日 18:55
  • 1697

Signals篇之后续实验部分

Note:上篇地址戳这里实验一 题目:wait系列函数和SIGCHILD的关系? 首先避免造轮子搜集下资料: CSDN博友 以上博友的分析有其不准确的地方,我做一点补充: wait的实现,不...
  • bushipeien
  • bushipeien
  • 2017年11月21日 12:11
  • 465

寒假第三天--栈和队列--数据结构实验之栈二:一般算术表达式转换成后缀式

数据结构实验之栈二:一般算术表达式转换成后缀式 Time Limit: 1000MS Memory limit: 65536K 题目描述 对于一个基于二元运算符的算术表达式,转换为对应的后缀...
  • u013015642
  • u013015642
  • 2014年01月16日 19:06
  • 1820

Job Control之后续实验(二)

题目一: 设计一段程序,设置子进程的process group id,使其子进程成为该group leader并考虑竞态的发生。 [root@localhost ~]# vim 9_1...
  • LoveStackover
  • LoveStackover
  • 2018年02月06日 21:26
  • 237

哈工大操作系统实验2—系统接口

实验步骤 (1)了解应用程序如何调用系统调用 在通常情况下,调用系统调用和调用一个普通的自定义函数在代码上并没有什么区别,但调用后发生的事情有很大不同。调用自定义函数是通过call指令直接跳转到该函数...
  • wangjianyu0115
  • wangjianyu0115
  • 2015年07月13日 21:07
  • 1434

Job Control后续实验(二)

NOTE :理论部分请戳 [戳我戳我](http://blog.csdn.net/bushipeien/article/details/78843724)题目一: 设计一段程序,设置子进程的pro...
  • bushipeien
  • bushipeien
  • 2017年12月20日 12:12
  • 288

编译原理实验二分析

对于 编译原理实验二 实验二主要分析实验一中的得到的多元式是进行计算器的语义分析 需要从实验1中获取分析成功的多元(种别码,字符串原貌,Value属性,Type属性)式序列 根据多元式中的Type属性...
  • ruihaol
  • ruihaol
  • 2017年01月18日 14:47
  • 664

数据结构实验二——栈和队列

1.1.编写一个程序,实现顺序栈的各种基本运算,并在此基础上设计一个主程序完成如下功能: (1)初始化栈s; (2)判断栈s是否为空; (3)依次进栈元素-1,2,10,-3,5; (4)判断...
  • u012736584
  • u012736584
  • 2015年05月08日 01:18
  • 966

Linux实验二:Linux 内核模块测试

一、实验目的 对Linux内核模块进行了解。 二、实验内容 创建一个内核模块,在加载和卸载模块时在内核中打印相关信息。 三、背景知识: 一、什么是内核模块?        内核模块是L...
  • longteng1116
  • longteng1116
  • 2013年04月10日 16:31
  • 2855

编译原理实验二——语法分析(预测分析)

[实验任务]1、实现LL(1)分析中控制程序(表驱动程序);2、完成以下描述算术表达式的LL(1)文法的LL(1)分析程序(LL(1)分析表见教材)。G[E]:        E→TE′       ...
  • ffee
  • ffee
  • 2006年05月31日 19:52
  • 6970
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:信号之后续实验部分(二)
举报原因:
原因补充:

(最多只允许输入30个字)