linux下C的信号函数(sig开头的那一簇)的实践

linux下C的信号函数(sig开头的那一簇)的实践。

 

背景知识:

linux操作系统中每个进程有一个信号中断列表,列表中每个信号对应一段操作逻辑。

进程收到信号(比如Ctlr+c,比如kill)后查询自己的中断列表,如果有该信号对应的处理逻辑,进程中断当前正在运行的处理逻辑,执行中断处理逻辑。

如果中断处理逻辑不是退出进程,那么它执行完毕后,原先被中断的处理逻辑继续运行。

进程的信号中断列表有一套C的信号函数( sig开头的这一 簇 )可以修改。


我实际要解决的问题如下:

1,进程A通知进程B中断当前操作, 执行一段中断逻辑;

2,但是进程B在进行关键操作时,不可以被A中断;

 

使用到的函数:

  • sigemptyset
  • signal
  • sigaddset
  • sigaction
  • sigprocmask
  • kill

//=======================进程B实现逻辑================================

#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>

 

//自定义的中断处理函数

void bProcessSignal(int signo, siginfo_t *info, void *context)
{
    printf("in bProcessSignal/n");
}

 

int main(int arg, char* argv[])
{

        // 将当前进程的进程号写入文件 /home/admin/.b_pid, 以便进程A读取


        char pidfilestr[256];
        char* homepath = getenv("HOME");
        if(NULL == homepath)
        {
                homepath = ".";
        }
        sprintf(pidfilestr, "%s/%s", homepath, ".b_pid");
       
        FILE *fp = fopen(pidfilestr, "w+");
        if (fp == NULL)
        {
                printf("in process B, fail to fopen =%s/n", pidfilestr);
                return 0;
        }
        fprintf(fp, "%d/n", getpid());
        fclose(fp);

 

        /*设置SIGPIPE信号被忽略

当服务器close一个连接时,若client端接着发数据。根据TCP协议的规定,会收到一个RST响应,client再往这个服务器发送数据时,系统 会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不要再写了。根据信号的默认处理规则SIGPIPE信号的默认执行动作是terminate(终止、退出),所以client会退出。若不想客户端退出可以把 SIGPIPE设为SIG_IGN

*/

        signal(SIGPIPE,SIG_IGN);

 

        /*设置SIGHUP信号被忽略

SIGHUP和控制台操作有关,当控制台被关闭时系统会向拥有控制台sessionID的所有进程发送HUP信号,默认HUP信号的action是 exit

*/
 signal(SIGHUP,SIG_IGN);

 

//action用于描述信号对应的操作逻辑

struct sigaction action;       

 

//清空初始化action的sa_mask成员(附加的屏蔽信号,)

sigemptyset(&action.sa_mask);

 

//设置中断处理逻辑函数入口

action.sa_sigaction=bProcessSignal;

 

/* 默认的中断处理函数形式 void handler(int signo);

如果设置sa_flags=SA_SIGINFO, 中断处理逻辑函数形式为 void handler(int signo, siginfo_t *info, void *context);

即设 置sa_flags=SA_SIGINFO,将使得中断处理函数获得更多的信息

*/

action.sa_flags=SA_SIGINFO;

 

//为信号SIGUSR2设置中断处理逻辑,成功设置返回0

//sigaction成功调用后,进程就可以被信号SIGUSR2中断而且使用指定的处理逻辑了

if(sigaction(SIGUSR2, &action, NULL) < 0)

{

printf("in sig_install : 安装信号处理函数错误/n");
return 0;

}

 

//sigset用于存放需要更新(添加)到进程的信号集, sigold用于保存进程更新前的信号集

        sigset_t sigset, sigold;

 

//清空初始化信号集sigset

sigemptyset(&sigset);

 

//在信 号集sigset中加入信号SIGUSR2
sigaddset(&sigset, SIGUSR2);

 

for(int i=0;i<100;++i)

{

/*使用SIG_BLOCK调用sigprocmask,并且有第二和第三个参数,效果是:

调用前的信号集合存入结构体sigold

sigset中的信号被屏蔽(block),即调用成功后,进程阻塞信号集sigset中的信号,单线程适用

因为在 sigset中存入了 信号SIGUSR2,所以下面的调用后, SIGUSR2信号对已进程是阻塞的

*/

sigprocmask(SIG_BLOCK, &sigset, &sigold));

{

//需要屏蔽 SIGUSR2中断处理逻辑的操作

key_operation_func();

}

 

/*使用SIG_SETMASK调用sigprocmask,并且只有第二个参数,效果是:

第二个参数表示的信号集合被设置为进程的信号集

因为在sigold是信号SIGUSR2被屏蔽前的快照,所以以下的函数被调用后,SIGUSR2 信号将被进程处理

*/

sigprocmask(SIG_SETMASK, &sigold, NULL));

sleep(1);

}

return 0;

}

 

//=======================进程A实现逻辑================================

int main(int arg, char* argv[])
{

        // 从文件 /home/admin/.b_pid中读取进程B的进程号


        char pidfilestr[256];
        char* homepath = getenv("HOME");
        if(NULL == homepath)
        {
                homepath = ".";
        }
        sprintf(pidfilestr, "%s/%s", homepath, ".b_pid");

        FILE* fp = fopen(apcupfile, "r");
        if (fp != NULL)
        {      
                char szData[50];
                memset(szData, '/0', 50);
                fgets(szData, 50, fp);
                fclose(fp);
                pid_t bpid = atoi(szData);

 

//使用0调用kill,不发送信号,检测bpid进程是否存在
if(kill(bpid , 0) == 0)
{  

 

//向bpid进程发送信号SIGUSR2
kill(bpid , SIGUSR2);
printf("send SIGUSR2 to %d %s", apcuppid, apcupfile);


}

}

return 0;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值