LinuxC应用开发学习笔记(十一)—并发(信号)

这篇博客深入探讨了信号处理的概念,包括同步与异步信号、信号的不可靠性以及可重入函数。文章通过实例展示了如何使用signal()、kill()、alarm()和setitimer()等函数来处理和响应信号,并讨论了信号集合的使用。此外,还介绍了守护进程的创建和实时信号的应用,以及如何在多线程环境中处理信号。最后,提到了信号驱动程序和实时信号的例子,强调了在高并发和实时性场景下的信号管理策略。
摘要由CSDN通过智能技术生成

信号

同步
异步:什么时候到来不知道,产生什么结果不知道
处理:查询法、通知法

一、信号(初步异步、强烈异步)

1、信号的概念

信号是软件中断。
信号的响应依赖于中断。

2、signal();

void signal(int signum,void (*func)(int )))(int);
信号会打断阻塞的系统调用。如:open 和 read

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void int_handler(int s)
{
    write(1,"!",1);
}

int main()
{
    int i;

    /*把打断信号忽略掉*/
    //signal(SIGINT,SIG_IGN);

    signal(SIGINT,int_handler);
    

    for (i = 0; i < 10; i++)
    {
        write(1,"*",1);
        sleep(1);
    }
    exit(0);
}

3、信号的不可靠

信号的行为不可靠,因为执行现场不可控。

4、可重入函数

所有的系统调用都是可重入的,一部分库函数也是可重入的,比如说:memcpy, localtime。函数有_r版本,原来的版本就不能用在信号处理中。

5、信号的响应过程

1)信号从收到到响应有一个不可避免的延迟。
思考:1、如何忽略掉一个信号的???
把指定信号的mask位置为0,阻止信号被响应。但是不能阻止信号到来。
2、标准信号为什么要丢失???
位图,来1W次还是置为1次1,不会累加,不会计数。
3、标准信号的响应没有严格的顺序。

每个进程都有这样的两个位图,当有一个信号发出的时候,pending会置1,然后mask&pending,从kernel态到user态有一个时延。
信号时从kernel到user的路上响应。
多线程再解释:mask置为0,是防止重入现象。

在这里插入图片描述

6、相关的常用函数

kill();
kill是用来给进程发出信号,
raise();
alarm();
里程碑式函数。有一个稍微准确点的时间。
setitimer();//精度控制更好,没有延迟累计的。

例:使用单一计时器构造一组函数,实现任意数量的计时器

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

int main()
{
    /*无法实现多任务的计数器,会调用最后一个alarm*/
    alarm(10);
    alarm(5);
    alarm(1);
    while (1)
        pause();
    
    exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>

int main()
{
    time_t end;
    long long count = 0;
    end = time(NULL) + 5;

    while (time(NULL) <= end)
    {
        count++;
    }
    printf("%lld\n",count);    
    exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <signal.h>

//易变符
static volatile int loop = 1;

static void alarm_handler(int s)
{
    loop = 0;
}

int main()
{
    long long count = 0;

    //触发信号,需要放在alarm之前
    signal(SIGALRM,alarm_handler);

    alarm(5);

    while (loop)
        count++;
    
    printf("%lld\n",count);

    
    exit(0);
}
漏桶实现
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFSIZE 1024


int main(int argc,char **argv)
{
    int sfd,dfd = 1;
    int ch,len,ret,pos = 0;
    char buf[BUFSIZE];


    if (argc < 2)
    {
        fprintf(stderr,"Usage : %s <source_filename> <dest_filename>\n",argv[0]);
        exit(1);
    }
    
    do
    {
        sfd = open(argv[1],O_RDONLY);
        if (sfd < 0)
        {
            if(errno != EINTR)
            {
                perror("open()");
                exit(1);
            }
        }
    } while (sfd < 0);
    

    while (1)
    {
        /*len read 10 byte*/
       len = read(sfd,buf,BUFSIZE);
        if (len<0)
        {
            if (errno == EINTR)
                continue;
            perror("read()");
            break;
        }
        if (len == 0)
        {
            break;
        }

        pos = 0;

        /*判断len是否全部填入*/
        while (len > 0)
        {
            /*from buf read len byte to dfd*/
            ret = write(dfd,buf+pos,len);
            if (ret < 0 )
            {
                if (errno == EINTR)
                    continue;
                perror("write()");
                exit(1);
            }
            /*计算下一个写入的位置*/
            pos += ret;
            /*计算剩下的没填入的字节数*/
            len -= ret;
        }
     
    }

    close(sfd);
    

    exit(0);
}
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>

#define CPS     10
#define BUFSIZE CPS

static volatile int loop = 0;

static  void alarm_handler(int s)
{
    alarm(1);
    loop = 1;
}

int main(int argc,char **argv)
{
    int sfd,dfd = 1;
    int ch,len,ret,pos = 0;
    char buf[BUFSIZE];

    if (argc < 2)
    {
        fprintf(stderr,"Usage : %s <source_filename> <dest_filename>\n",argv[0]);
        exit(1);
    }
     
    signal(SIGALRM,alarm_handler);
    alarm(1);

    do
    {
        sfd = open(argv[1],O_RDONLY);
        if (sfd < 0)
        {
            if(errno != EINTR)
            {
                perror("open()");
                exit(1);
            }
        }
    } while (sfd < 0);
    

    while (1)
    {

        while(!loop)
            ;
        loop = 0;

        /*len read 10 byte*/
        while(len = read(sfd,buf,BUFSIZE)<0)
        {
            if (errno == EINTR)
                continue;
            perror("read()");
            break;
        }
        if (len == 0)
            break;

        pos = 0;

        /*判断len是否全部填入*/
        while (len > 0)
        {
            /*from buf read len byte to dfd*/
            ret = write(dfd,buf+pos,len);
            if (ret < 0 )
            {
                if (errno == EINTR)
                    continue;
                perror("write()");
                exit(1);
            }
            /*计算下一个写入的位置*/
            pos += ret;
            /*计算剩下的没填入的字节数*/
            len -= ret;
        }
    }

    close(sfd);
    
    exit(0);
}
slowcat重构
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>

#define CPS     10
#define BUFSIZE CPS
#define BURST   100 


/*保证赋值操作一定是一条机器指令完成的*/
static volatile sig_atomic_t token = 0;

static void alarm_handler(int s)
{
    alarm(1);
    token++;
    if (token > 100)
    {
        token = BURST;
    }   
}

int main(int argc,char **argv)
{
    int sfd,dfd = 1;
    int ch,len,ret,pos = 0;
    char buf[BUFSIZE];

    if (argc < 2)
    {
        fprintf(stderr,"Usage : %s <source_filename> <dest_filename>\n",argv[0]);
        exit(1);
    }
    
    /*给SIGALRM发送信号*/
    signal(SIGALRM,alarm_handler);
    alarm(1);

    do
    {
        sfd = open(argv[1],O_RDONLY);
        if (sfd < 0)
        {
            if(errno != EINTR)
            {
                perror("open()");
                exit(1);
            }
        }
    } while (sfd < 0);
    

    while (1)
    {

        while(token <= 0)
            pause();//等待一个系统调用,暂时去掉盲等的情况。
        token--;

        /*len read 10 byte*/
        while(len = read(sfd,buf,BUFSIZE)<0)
        {
            if (errno == EINTR)
                continue;
            perror("read()");
            break;
        }
        if (len == 0)
            break;

        pos = 0;

        /*判断len是否全部填入*/
        while (len > 0)
        {
            /*from buf read len byte to dfd*/
            ret = write(dfd,buf+pos,len);
            if (ret < 0 )
            {
                if (errno == EINTR)
                    continue;
                perror("write()");
                exit(1);
            }
            /*计算下一个写入的位置*/
            pos += ret;
            /*计算剩下的没填入的字节数*/
            len -= ret;
        }
    }

    close(sfd);
    
    exit(0);
}

pause();

abort();
给当前进程发送 abort信号。人为制造一个异常,杀掉当前进程得到出错的现场。

system();
调用shell完成shell。

sleep();
sleep有问题是因为sleep是 alarm和pause加起来封装的。当前没有错是因 为sleep使用nanosleep封装的。可以使用nanosleep,usleep替代。

usleep();
nanosleep();
select();

令牌桶
#ifndef MYTBF_H__
#define MYTBF_H__ 

#define  MYTBF_MAX  1024

typedef void mytbf_t;


mytbf_t *mytbf_init(int cps,int burst);

/*取令牌*/
int mytbf_fetchtoken(mytbf_t *,int );

/*归还令牌*/
int mytbf_returntoken(mytbf_t *,int );

int mytbf_destory(mytbf_t *);

#endif // DEBUG
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include "mytbf.h"

static __sighandler_t alarm_handler_save;

static struct mytbf_st* job[MYTBF_MAX];

static int inited = 0;

struct mytbf_st
{
    int cps;//每秒传输的字节数
    int burst;//传输的上限
    int token;//令牌桶
    int pos;//下标
};

static void alarm_handler(int s)
{
    int i;

    alarm(1);

    for (i = 0; i < MYTBF_MAX; i++)
    {
        if (job[i] != NULL)
        {
            job[i]->token += job[i]->cps;
            if (job[i]->token>job[i]->burst)
                 job[i]->token = job[i]->burst;
            
        }       
    }
}

/*模块卸载,保持进出的状态都一致*/
static void module_unload(void)
{
    int i;
    /*恢复功能*/
    signal(SIGALRM,alarm_handler_save);
    alarm(0);
    for (i = 0; i < MYTBF_MAX; i++)
        free(job[i]);
}

static void module_load(void)
{
    alarm_handler_save = signal(SIGALRM,alarm_handler);

    alarm(1);

    atexit(module_unload);
}

static int get_free_pos(void)
{
    int i;
    for (i = 0; i < MYTBF_MAX; i++)
    {
        if (job[i] == NULL)
            return i;   
    }
    return -1;
}

static int min(int a,int b)
{
    if (a<b)
        return a;
    return b;
}

mytbf_t *mytbf_init(int cps,int burst)
{
    struct mytbf_st *me;

    int pos;

    if (!inited)
    {
        module_load();
        inited = 1;
    }
       
    pos = get_free_pos();
    if (pos < 0)
        return NULL;
    
    me = malloc(sizeof(*me));
    if (me == NULL)
        return NULL;

    me->token = 0;
    me->cps = cps;
    me->burst = burst;
    me->pos = pos;

    job[pos] = me;

    return me;

}


/*取令牌*/
int mytbf_fetchtoken(mytbf_t *ptr,int size)
{
    struct mytbf_st *me = ptr;//指针转换

    int n;

    if (size <= 0)
       return -EINVAL;

    while(me->token <= 0)
        pause();//等待,阻塞的实现

    n = min(me->token,size);

    me->token -= n;

    return n;
    
}


/*归还令牌*/
int mytbf_returntoken(mytbf_t *ptr,int size)
{
    struct mytbf_st *me = ptr;//指针转换

    if (size <= 0)
       return -EINVAL;

    me->token += size;

    if (me->token > me->burst)
        me->token = me->burst;

    return size;
      
}

int mytbf_destory(mytbf_t *ptr)
{
    struct mytbf_st *me = ptr;//指针转换

    job[me->pos] = NULL;

    free(ptr);

    return 0; 
}

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include "mytbf.h"

#define CPS     10
#define BUFSIZE 1024
#define BURST   100 

int main(int argc,char **argv)
{
    int sfd,dfd = 1;

    int size;

    int ch,len,ret,pos = 0;

    char buf[BUFSIZE];

    mytbf_t *tbf;


    if (argc < 2)
    {
        fprintf(stderr,"Usage : %s <source_filename> <dest_filename>\n",argv[0]);
        exit(1);
    }
    
    tbf = mytbf_init(CPS,BURST);
    if (tbf == NULL)
    {
        fprintf(stderr,"mytbf_init()failed\n");
        exit(1);
    }
    
    do
    {
        sfd = open(argv[1],O_RDONLY);
        if (sfd < 0)
        {
            if(errno != EINTR)
            {
                perror("open()");
                exit(1);
            }
        }
    } while (sfd < 0);
    

    while (1)
    {

        size =  mytbf_fetchtoken(tbf,BUFSIZE);
        if (size < 0)
        {
            fprintf(stderr,"mytbf_fetchtoken():%s\n",strerror(-size));

            exit(1);
        }
        
        /*len read 10 byte*/
        while(len = read(sfd,buf,size)<0)
        {
            if (errno == EINTR)
                continue;
            perror("read()");
            break;
        }

        if (len == 0)
            break;

        if (size - len>0)
            mytbf_returntoken(tbf,size-len);
        
        pos = 0;

        /*判断len是否全部填入*/
        while (len > 0)
        {
            /*from buf read len byte to dfd*/
            ret = write(dfd,buf+pos,len);
            if (ret < 0 )
            {
                if (errno == EINTR)
                    continue;
                perror("write()");
                exit(1);
            }
            /*计算下一个写入的位置*/
            pos += ret;
            /*计算剩下的没填入的字节数*/
            len -= ret;
        }
    }

    close(sfd);
    
    mytbf_destory(tbf);

    exit(0);
}
anytime实现

.c文件

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/time.h>
#include "anytimer.h"

enum
{
    STATE_RUNNING = 1,
    STATE_CANCEL,
    STATE_OVER
};

struct at_job_st
{
    int job_state;
    
    int sec;
    
    int time_remain;

    at_addjob_t *jobp;

    void *arg;
};

static struct at_job_st *job[JOB_MAX];

static int inited = 0;

static struct sigaction alrm_sa_save;

static void alrm_action(int s,siginfo_t *infop,void *unused)
{
    int i;
    if (infop->si_code != SI_KERNEL)
        return;
    for ( i = 0; i < JOB_MAX; i++)
    {
        if(job[i]->job_state == STATE_RUNNING&&job[i]!=NULL)
        {
            job[i]->time_remain--;
            if(job[i]->time_remain == 0)
            {
                job[i]->jobp(job[i]->arg);
                job[i]->job_state = STATE_OVER;
            }

        }
    }
    
    


}

static void module_unload(void)
{
    struct sigaction sa,alrm_sa_save;

    struct itimerval itv;

    sa.sa_sigaction = alrm_action;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;

    if (sigaction(SIGALRM,&sa,&alrm_sa_save)<0)
    {
        perror("sigaction()");
        exit(1);
    }
    itv.it_interval.tv_sec  = 1;
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec     = 1;
    itv.it_value.tv_usec    = 0;
    if (setitimer(ITIMER_REAL,&itv,NULL)<0)
    {
        perror("setitimer()");
        exit(1);
    }

}

static void module_load(void)
{   
    struct itimerval itv;
    itv.it_interval.tv_sec  = 0;
    itv.it_interval.tv_usec = 0;
    itv.it_value.tv_sec     = 0;
    itv.it_value.tv_usec    = 0;
    setitimer(ITIMER_REAL,&itv,NULL);
  
    if (sigaction(SIGALRM,&alrm_sa_save,NULL)<0)
    {
        perror("sigaction()");
        exit(1);
    }

    atexit(module_unload);
}





static int get_free_pos(void)
{
    int i;
    for ( i = 0; i < JOB_MAX; i++)
    {
        if (job[i] == NULL)
            return i;  
    } 
}

int at_addjob(int sec,at_addjob_t *jobp,void* arg)
{
    int pos;

    struct at_job_st *me;

    //只调用一次函数
    if (!inited)
    {
        module_load();
        inited = 1;
    }

    pos = get_free_pos();
    if (pos<0)
        return -ENOSPC;
    
    me = malloc(sizeof(*me));
    if (me == NULL)
        return -ENOMEM;

    //初始化
    me->job_state = STATE_RUNNING;
    me->sec = sec;
    me->time_remain = me->sec;
    me->jobp = jobp;
    me->arg = arg;
    job[pos] = me;

    return pos;
    

}

int at_canceljob(int id)
{
    if (id < 0 || id>=JOB_MAX||job[id] == NULL)
        return -EINVAL;
    
    if (job[id]->job_state == STATE_CANCEL)
        return -ECANCELED;
    if (job[id]->job_state == STATE_OVER)
        return -EBUSY;
    
    job[id]->job_state = STATE_CANCEL;

    return 0;
}

int at_waitjob(int id)
{   
    if (id < 0 || id >= JOB_MAX||job[id] == NULL)
        return -EINVAL;
    while(job[id]->job_state == STATE_RUNNING)
        pause();
    if (job[id]->job_state == STATE_CANCEL||job[id]->job_state == STATE_OVER)
    {
        free(job[id]);
        job[id] = NULL;
    }    
}

.h文件

#ifndef MYTBF_H__
#define MYTBF_H__ 

#define JOB_MAX 1024 

typedef void at_addjob_t(void*);



int at_addjob(int sec,at_addjob_t *jobp,void* arg);
/*
* return >= 0 成功,返回任务ID
*        == -EINVAL 失败,参数非法
*        == -ENOSPC 失败,数组满
*        == -ENOMEM 失败,内存空间不足 
**/

int at_addjob_repeat(int sec,at_addjob_t *jobp,void* arg);
/*
* return >= 0 成功,返回任务ID
*        == -EINVAL 失败,参数非法
*        == -ENOSPC 失败,数组满
*        == -ENOMEM 失败,内存空间不足 
**/

int at_canceljob(int id);
/*
* return == 0 取消,指定任务成功取消
*        == -EINVAL 失败,参数非法
*        == -EBUSY  失败,任务已完成 
*        == -ECANCELED 失败,指定任务重复取消 
**/
int at_waitjob(int id);
/*
* return == 0 取消,指定任务成功释放
*        == -EINVAL 失败,参数非法
**/


#endif

main.c

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <errno.h>


static void f1(void *p)
{
    printf("f1():%s\n",p);
}

static void f2(void *p)
{
    printf("f2():%s\n",p);
}



int main(int argc,char **argv)
{
    int job1,job2,job3;

    puts("Begin!");

    job1 = at_addjob(5,f1,"aaa");
    if (job1 < 0)
    {
        fprintf(stderr,"at_addjob():%s\n",strerror(-job1));
        exit(1);
    }
    

    at_addjob(2,f2,"bbb");

    at_addjob(7,f1,"ccc");

    puts("End!");
    

}

7、信号集合

信号集类型:sigset_t

sigemptyset();
sigfillset();
sigaddset();
sigdelset();
sigismember();

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>

void int_handler(int s)
{
    write(1,"!",1);
}

int main()
{
    int i,j;

    /*把打断信号忽略掉*/
    //signal(SIGINT,SIG_IGN);
    sigset_t set,oset,saveset;

    signal(SIGINT,int_handler);

    sigemptyset(&set);

    sigaddset(&set,SIGINT);

    sigprocmask(SIG_BLOCK,&set,&oset);
    
    for (j = 0; i < 1000; j++)
    {
            /*代码执行过程中,不受信号影响*/
            sigprocmask(SIG_BLOCK,&set,&oset);
            for (i = 0; i < 5; i++)
            {
                write(1,"*",1);
                sleep(1);
            }
            write(1,"\n",1);
            /*解除阻塞,返回之前的状态*/
            sigprocmask(SIG_SETMASK,&oset,NULL);
    }
    sigprocmask(SIG_SETMASK,&saveset,NULL);

    /*一头一尾表示进入这个状态和出去这个状态是没有影响的*/
    exit(0);
}

8、信号屏蔽字/pending集合的处理

sigprocmask();//相当于给一种机会来人为的控制mask。不能确定信号什么时候到来,但是可以确定信号什么时候被响应。
sigpending();//不知道用在什么环境下

9、扩展

sigsuspend();

信号驱动程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>

void int_handler(int s)
{
    write(1,"!",1);
}

int main()
{
    int i,j;

    /*把打断信号忽略掉*/
    //signal(SIGINT,SIG_IGN);
    sigset_t set,oset,saveset;

    signal(SIGINT,int_handler);

    sigemptyset(&set);

    sigaddset(&set,SIGINT);

    sigprocmask(SIG_UNBLOCK,&set,&saveset);

    sigprocmask(SIG_BLOCK,&set,&oset);

    for (j = 0; i < 1000; j++)
    {
        /*代码执行过程中,不受信号影响*/
        
        for (i = 0; i < 5; i++)
        {
            write(1,"*",1);
            sleep(1);
        }
        write(1,"\n",1);
        sigsuspend(&oset);//相当于如下的原子操作。
        /*解除阻塞,返回之前的状态*/
        /*
        sigset_t tmpset;
        sigprocmask(SIG_SETMASK,&oset,&tmpset);
        pause();
        sigprocmask(SIG_SETMASK,&tmpset,NULL);
        */
    }
   sigprocmask(SIG_SETMASK,&saveset,NULL);

    exit(0);
}

sigaction();

setitimer();

守护进程的重构
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <glob.h>
#include <syslog.h>
#include <errno.h>
#include <signal.h>

#define FNAME "tmp/out" 

static FILE *fp;
/*多个信号可以共用同一个信号处理函数*/
static void daemon_exit(int s)
{

    fclose(fp);
    closelog();
}

static int daemonize()
{
    pid_t pid;
    int fd;
    pid = fork();
    if (pid<0)
        return -1;

    
    if (pid>0)  //parent
    {
        exit(0);
    }
    fd = open("/dev/null",O_RDWR);
    if (fd<0)
        return -1;
    //将来要脱离控制终端的,0、1、2不需要关联设备,因此需要重定向。
    dup2(fd,0);
    dup2(fd,1);
    dup2(fd,2);
    if (fd > 2)
    {
        close(fd);
    }
    
    setsid();
    chdir("/");
    return 0;
}


int main()
{
    
    int i;
    //当你受到INTERRUPT这个信号的时候,就来执行 
    struct sigaction sa;
    sa.sa_handler = daemon_exit;
    __sigemptyset(&sa.sa_mask);
    __sigaddset(&sa.sa_mask,SIGQUIT);
    __sigaddset(&sa.sa_mask,SIGTERM);
    __sigaddset(&sa.sa_mask,SIGINT);
    sa.sa_flags = 0;

    sigaction(SIGINT,&sa,NULL);
    sigaction(SIGTERM,&sa,NULL);
    sigaction(SIGQUIT,&sa,NULL);
    

    openlog("mydaemon",LOG_PID,LOG_DAEMON);

    if (daemonize())
    {
        syslog(LOG_ERR,"daeonize() failed!");
        exit(1);
    }
    else
    {
        syslog(LOG_INFO,"daemonize() successded!"); 
    }
    
    fp = fopen(FNAME,"w");
    if (fp == NULL)
    {
        syslog(LOG_ERR,"fopen():%s",strerror(errno));
        exit(1);
    }

    syslog(LOG_INFO,"%s was opened.",FNAME);

    for (i = 0; ; i++)
    {
        
        fprintf(fp,"%d\n",i);
        fflush(fp);
        syslog(LOG_DEBUG,"%d is printed",i);
        sleep(1);
    }
    
    fclose(fp);
    closelog();
    
    exit(0);
}
令牌桶改装sigaction
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include "mytbf.h"

static struct mytbf_st* job[MYTBF_MAX];

static int inited = 0;

static struct sigaitvction alrm_sa_save;

struct mytbf_st
{
    int cps;//每秒传输的字节数
    int burst;//传输的上限
    int token;//令牌桶
    int pos;//下标
};

static void alrm_action(int s,siginfo_t *infop,void *unused)
{

    int i;

    //alarm(1);

    if (infop->si_code != SI_KERNEL)
        return;
    

    for (i = 0; i < MYTBF_MAX; i++)
    {
        if (job[i] != NULL)
        {
            job[i]->token += job[i]->cps;
            if (job[i]->token>job[i]->burst)
                 job[i]->token = job[i]->burst;
            
        }
        
    }

}

/*模块卸载,保持进出的状态都一致*/
static void module_unload(void)
{
    int i;
    /*恢复功能*/
    struct itimerval itv;


    sigaction(SIGALRM,&alrm_sa_save,NULL);


    itv.it_interval.tv_sec = 0;
    itv.it_interval.tv_usec =0;
    itv.it_value.tv_sec = 0;
    itv.it_value.tv_usec = 0;
     setitimer(ITIMER_REAL,&itv,NULL);

    for (i = 0; i < MYTBF_MAX; i++)
        free(job[i]);
}


static void module_load(void)
{

    struct sigaction sa;
    struct itimerval itv;


    sa.sa_sigaction = alrm_action;
    __sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO; 

    

    sigaction(SIGALRM,&sa,&alrm_sa_save);
    /*if error*/


    itv.it_interval.tv_sec = 1;
    itv.it_interval.tv_usec =0;
    itv.it_value.tv_sec =1;
    itv.it_value.tv_usec = 0;
    setitimer(ITIMER_REAL,&itv,NULL);
    /*if error*/



    atexit(module_unload);
}

static int get_free_pos(void)
{
    int i;
    for (i = 0; i < MYTBF_MAX; i++)
    {
        if (job[i] == NULL)
            return i;   
    }
    return -1;
}

static int min(int a,int b)
{
    if (a<b)
        return a;
    return b;
}

mytbf_t *mytbf_init(int cps,int burst)
{
    struct mytbf_st *me;

    int pos;

    if (!inited)
    {
        module_load();
        inited = 1;
    }
    
    
    pos = get_free_pos();
    if (pos < 0)
        return NULL;
    
    me = malloc(sizeof(*me));
    if (me == NULL)
        return NULL;

    me->token = 0;
    me->cps = cps;
    me->burst = burst;
    me->pos = pos;

    job[pos] = me;

    return me;

}


/*取令牌*/
int mytbf_fetchtoken(mytbf_t *ptr,int size)
{
    struct mytbf_st *me = ptr;//指针转换

    int n;

    if (size <= 0)
       return -EINVAL;

    while(me->token <= 0)
        pause();//等待,阻塞的实现

    n = min(me->token,size);

    me->token -= n;

    return n;
    
}


/*归还令牌*/
int mytbf_returntoken(mytbf_t *ptr,int size)
{
    struct mytbf_st *me = ptr;//指针转换

    if (size <= 0)
       return -EINVAL;

    me->token += size;

    if (me->token > me->burst)
        me->token = me->burst;

    return size;      
}

int mytbf_destory(mytbf_t *ptr)
{
    struct mytbf_st *me = ptr;//指针转换

    job[me->pos] = NULL;

    free(ptr);

    return 0; 
}

10、实时信号

实时信号和标准信号。当信号同时发生的时候,先响应标准信号。

实时信号示例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>

#define  MYRTSIG (SIGRTMIN+6) 

void mysig_handler(int s)
{
    write(1,"!",1);
}

int main()
{
    int i,j;

    /*把打断信号忽略掉*/
    //signal(SIGINT,SIG_IGN);
    sigset_t set,oset,saveset;

    signal(MYRTSIG,mysig_handler);

    sigemptyset(&set);

    sigaddset(&set,MYRTSIG);

    sigprocmask(SIG_UNBLOCK,&set,&saveset);

    sigprocmask(SIG_BLOCK,&set,&oset);

    for (j = 0; i < 1000; j++)
    {
        /*代码执行过程中,不受信号影响*/
        
        for (i = 0; i < 5; i++)
        {
            write(1,"*",1);
            sleep(1);
        }
        write(1,"\n",1);
        sigsuspend(&oset);//相当于如下的原子操作。
        /*解除阻塞,返回之前的状态*/
        /*
        sigset_t tmpset;
        sigprocmask(SIG_SETMASK,&oset,&tmpset);
        pause();
        sigprocmask(SIG_SETMASK,&tmpset,NULL);
        */
    }
   sigprocmask(SIG_SETMASK,&saveset,NULL);

    exit(0);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值