今天继续探讨信号相关的东东,话不多说,正入正题:
![](https://i-blog.csdnimg.cn/blog_migrate/0300dab204159927897092d071f1c816.png)
![](https://i-blog.csdnimg.cn/blog_migrate/38e9a7cb579344ce79cae99001c103d9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/142504fe851b2b6ecadb71c968607220.png)
![](https://i-blog.csdnimg.cn/blog_migrate/059a0cc492c6e7a6478bb74ca6f84225.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e7b1f362f1faf6cc0a1fed67716cb4c0.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fc7e2b069815703b807331b0b405bb49.png)
![](https://i-blog.csdnimg.cn/blog_migrate/6cabfc6aa36709db31b03b4345848084.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9a49b462b02ddf9a58cc8f788bcbef5e.png)
![](https://i-blog.csdnimg.cn/blog_migrate/06ee7a36ee85f504987330e5e1c4d346.png)
![](https://i-blog.csdnimg.cn/blog_migrate/1efc960d7e3f60b3c6d7b2f845373794.png)
![](https://i-blog.csdnimg.cn/blog_migrate/cb5b03a50abf1e796b1037cf4f492caa.png)
![](https://i-blog.csdnimg.cn/blog_migrate/578fe76d45ba8acd442b553efcf7e3ae.png)
![](https://i-blog.csdnimg.cn/blog_migrate/dee801d060b68c8734a6bee04d650ff2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/db0af6439ee5dc98f023efbf3b59cde7.png)
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
void handler(int sig);
void printsigset(sigset_t *set)//打印出信号集的状态,其中参数set为未诀状态的信号集
{
int i;
for (i=1; i<NSIG; ++i)//NSIG表示信号的最大值,也就是等于64
{
if (sigismember(set, i))//说明是未诀状态的信号
putchar('1');
else
putchar('0');//说明不是未诀状态的信号
}
printf("\n");
}
int main(int argc, char *argv[])
{
sigset_t pset;
for (;;)
{
sigpending(&pset);//该函数是获取进程当中未诀状态的信号集 ,保存在pset当中
printsigset(&pset);//打印信号集的状态,看有没有未诀状态的信号产生
sleep(1);
}
return 0;
}
【说明】:sigpending是用来获取进程中所有的未诀信号集:
![](https://i-blog.csdnimg.cn/blog_migrate/29466c8f8053e34240bca20f1b4ac4b4.png)
这时看一下运行效果:
![](https://i-blog.csdnimg.cn/blog_migrate/975b25c432b57fd22ba10ac9e5189a00.gif)
可以发现,当前状态没有未诀的信号,因为还没有被阻塞的信号过,信号也没有产生过,所以不可能有未诀的状态。
这时,我们来安装一个SIGINT信号:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
void handler(int sig);
void printsigset(sigset_t *set)
{
int i;
for (i=1; i<NSIG; ++i)
{
if (sigismember(set, i))
putchar('1');
else
putchar('0');
}
printf("\n");
}
int main(int argc, char *argv[])
{
sigset_t pset;
if (signal(SIGINT, handler) == SIG_ERR)//安装一个SIGINT信号
ERR_EXIT("signal error");
for (;;)
{
sigpending(&pset);
printsigset(&pset);
sleep(1);
}
return 0;
}
void handler(int sig)
{
printf("recv a sig=%d\n", sig);
}
这时再看下效果:
![](https://i-blog.csdnimg.cn/blog_migrate/6713de0aa7d96018b38da069212285bb.gif)
从结果来看,信号被直接递达了,所以这次也没有看到有1的未诀状态的信号,因为信号必须被阻塞才会出现未诀状态,所以接下来将SIGINT信号利用上面介绍到的函数来将其阻塞掉:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
void handler(int sig);
void printsigset(sigset_t *set)
{
int i;
for (i=1; i<NSIG; ++i)
{
if (sigismember(set, i))
putchar('1');
else
putchar('0');
}
printf("\n");
}
int main(int argc, char *argv[])
{
sigset_t pset;
sigset_t bset;
sigemptyset(&bset);//将信号集清0
sigaddset(&bset, SIGINT);//将SIGINT所对应的位置1
if (signal(SIGINT, handler) == SIG_ERR)
ERR_EXIT("signal error");
sigprocmask(SIG_BLOCK, &bset, NULL);//更改进程中的信号屏蔽字,其中第三个参数传NULL,因为不关心它原来的信号屏蔽字
for (;;)
{
sigpending(&pset);
printsigset(&pset);
sleep(1);
}
return 0;
}
void handler(int sig)
{
printf("recv a sig=%d\n", sig);
}
编译运行:
![](https://i-blog.csdnimg.cn/blog_migrate/e6c1074d604c5548e9c2ca6ec0c4ef42.gif)
从结果来看,将SIGINT信号来了,由于添加到了信号屏蔽字为1,所以会被阻塞掉,并且可以看到SIGINT对应的位也打印为1了。
【说明】:SIGINT对应的位是指:
![](https://i-blog.csdnimg.cn/blog_migrate/96d880aa9a5ac29c49e3c3c2733c054b.png)
下面,我们做一件事情,就是当我们按下ctrl+\解除阻塞,这样处于未诀状态的信号就会被递达,则对应的未诀状态位也会还原成0,具体代码如下:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
void handler(int sig);
void printsigset(sigset_t *set)
{
int i;
for (i=1; i<NSIG; ++i)
{
if (sigismember(set, i))
putchar('1');
else
putchar('0');
}
printf("\n");
}
int main(int argc, char *argv[])
{
sigset_t pset;
sigset_t bset;
sigemptyset(&bset);
sigaddset(&bset, SIGINT);
if (signal(SIGINT, handler) == SIG_ERR)
ERR_EXIT("signal error");
if (signal(SIGQUIT, handler) == SIG_ERR)//注册一个ctrl+c信号
ERR_EXIT("signal error");
sigprocmask(SIG_BLOCK, &bset, NULL);
for (;;)
{
sigpending(&pset);
printsigset(&pset);
sleep(1);
}
return 0;
}
void handler(int sig)
{
if (sig == SIGINT)
printf("recv a sig=%d\n", sig);
else if (sig == SIGQUIT)
{
sigset_t uset;//当按下ctrl+\时,则对SIGINT信号解除阻塞
sigemptyset(&uset);
sigaddset(&uset, SIGINT);
sigprocmask(SIG_UNBLOCK, &uset, NULL);
}
}
编译运行:
![](https://i-blog.csdnimg.cn/blog_migrate/dcf585381324e093c2ea3168061b8f27.gif)
从中可以看到,当我们按下ctrl+\时,并没有退出,而是解除了阻塞,所以对应的SIGINT位也变为0了。
另外,看下这种情况:
![](https://i-blog.csdnimg.cn/blog_migrate/ebfc7a8d3778738fe23f3cab42d89009.gif)
多次按了ctrl+c,可在按ctrl+\解除阻塞时,只响应了一次信号处理函数,这也由于SIGINT是不可靠信号,不支持排队。
另外,由于我们捕获了ctrl+\信号,所以没办法退出这个进程了,那怎么办呢,可以利用shell命令将其强制杀掉如下:
![](https://i-blog.csdnimg.cn/blog_migrate/15325790ed911e5a62d65e0de2cbcb18.gif)
好了,今天学的东西可能有些生涩,需好好消化,下节再见!