LoveStackover的博客

编程小子

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

实验一

题目: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中断,返回错误信息,终止程序。

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LoveStackover/article/details/79284098
个人分类: UNIX C编程
想对作者说点什么? 我来说一句

信号与系统实验一、二、三

2013年09月23日 258KB 下载

微弱信号检测实验报告

2018年04月22日 166KB 下载

没有更多推荐了,返回首页

不良信息举报

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

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭