微信开放平台 网站开发,百度法务部联系方式,wordpress通过微信投稿,wordpress金融主题目录 概念信号产生信号注册信号注销信号处理实例 信号的基本应用 概念 进程信号#xff1a; 概念#xff1a;信号就是软件中断。信号就是用于向进程通知某个事件的产生#xff0c;打断进程当前操作#xff0c;去处理这个事件。 linux中信号的种类#xff1a;使用kill -l命… 目录 概念信号产生信号注册信号注销信号处理实例 信号的基本应用 概念 进程信号 概念信号就是软件中断。信号就是用于向进程通知某个事件的产生打断进程当前操作去处理这个事件。 linux中信号的种类使用kill -l命令查看所有信号–62种 1~31非可靠信号有可能会造成事件丢失 34~64可靠信号不会丢失事件 信号的生命周期产生信号-在进程pcb中注册信号-注销信号-处理信号 信号产生 信号的产生 硬件产生 ctrlc 退出进程 ctrl| 退出进程 ctrlz 暂停进程此时ps -aux | grep 进程名称 可以看到进程处于停止状态。jobs查看作业通过fg 作业id让停止作业继续运行 软件产生 kill命令发送信号给指定进程 kill -signum pid kill命令杀死一个进程的原理默认给进程发送了终止信号 int kill(pid_t pid, int sig); 给pid进程发送sig信号 int raise(int sig); – 给进程自身发送一个指定的信号 unsigned int alarm(unsigned int seconds); –sec秒之后给进程自身发送一个时钟信号–SIGALRM void abort(void); – 给进程自身发送一个SIGABRT信号 int sigqueue(pid_t pid, int sig, const union sigval value); 给一个进程发送信号的同时携带一个数据过去 信号注册 信号的注册 注册在进程中注册一个信号让进程直到自己收到了某个信号 修改pending位图用于标记是否收到了某个信号添加一个信号信息节点 非可靠如果信号没有被注册则注册否则什么都不做。链表中不会出现相同非可靠信号信息节点 可靠不管信号是否注册都会注册一下。链表中有可能又多个相同的信号信息节点。 sigqueue-双向链表 – 表示有多少信号 信号注销 信号的注销 注销将信号信息进程pcb中一处修改位图删除节点 非可靠删除节点修改位图为0 可靠删除一个信号节点检查链表中是否还有相同节点没有则修改位图 信号处理 信号的处理 处理信号的处理也叫信号的递达实际上就是打断进程当前的操作去执行进程的对应信号处理函数。 信号的处理方式 1.默认处理方式 2.忽略处理方式 3.自定义处理方式–用户自己定义信号的处理回调函数 typedef void(*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); signum:信号值-表示要修改哪个信号的处理方式 handler新的信号处理方式 SIG_DEL-默认SIG_IGN-忽略自定义函数的名称 返回值成功则返回当前信号原来的处理方式 自定义处理方式的信号捕捉流程 信号是从程序运行从内核态返回用户态之前处理的。 程序处理信号时在内核态当遇到回调函数自定义时因为自定义函数是用户自己写的返回用户态执行完成后如果还有信号则继续返回内核态进行当信号处理完成后返回用户态主流程。 程序运行可以通过中断异常系统调用从用户态运行切换到内核态 #includestdio.h
#includeunistd.h
#includestdlib.h
#includesignal.hvoid sigcb(int signo)
{printf(recv signal:%d\n, signo);printf(时间到了\n);alarm(3);
}
int main(int argc, char *argv[])
{signal(信号处理方式)signal(SIGALRM, sigcb);kill(进程ID,信号值)//kill(getpid(), SIGINT);//raise(SIGINT);alarm(3);while(1){printf(-----\n);sleep(1);}return 0;
}阻塞信号的阻塞–阻止信号被递达 一个信号被阻塞后依然收到这个信号会注册但是暂时不被处理 pcb中有pending位图-未决信号结合还有阻塞信号集合 如果要阻塞一个信号就是在进程的阻塞信号集合中标记这个信号 具体操作 int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); how:操作类型 SIG_BLOCK-- 阻塞set集合的信号 block block | set SIG_UNBLOCK – 将set集合中的信号解除阻塞 block ~set SIG_SETMASK–将set集合中的信号设置为阻塞集合的信号blockset 返回值成功返回0失败返回-1 实例
先自定义特定信号的处理方式–做打印收到了哪个信号 signal 将所有信号阻塞 sigprocmask block 让程序运行停下来在这期间给进程发送信号getchar 解除这些信号的阻塞查看信号处理结果 sigprocmask unblock
#includestdio.h
#includeunistd.h
#includestdlib.h
#includesignal.hvoid sigcb(int signo)
{printf(recv signal:%d\n, signo);
}
int main(int argc, char *argv[])
{signal(SIGINT, sigcb);signal(40, sigcb);sigset_t set;sigemptyset(set);sigfillset(set);//zu sesigprocmask(SIG_BLOCK, set, NULL);printf(回车后,继续运行\n);getchar();printf(解除信号阻塞,查看结果\n);sigprocmask(SIG_UNBLOCK, set, NULL);while(1){sleep(1);}return 0;
}通过实例按三次ctrl c输入四次kill -40命令。最终结果显示ctrl c一次kill -40四次。 因为ctrl c是SIGINT在前31属于不可靠信号因此同时发送阻塞只保留一个。kill -40属于可靠信号每次发送都保留等阻塞结束后依次回调。 两个比较特殊的信号SIGKILL/SIGSTOP 这两个信号不可被阻塞不可被自定义不可被忽略说白了就是无法修改处理方式。 信号的基本应用 信号的基本应用 SIGCHLD信号一个子进程退出后给父进程发送的子进程状态改变信号 但是SIGCHLD默认处理方式就是什么都不做 要避免僵尸进程则需要在父进程中wait阻塞等待。 如果不想阻塞等待则可以使用信号来解决 自定义SIGCHLD信号的处理方式在回调函数中调用waitpid接口 SIGCHLD是一个非可靠信号–意味着多个子进程同时退出有可能丢失事件 signal(SIGCHLD,SIG_IGN);–显式忽略 #includestdio.h
#includeunistd.h
#includestdlib.h
#includesignal.h
#includesys/wait.hvoid sigcb(int no)
{printf(son fork exit\n);waitpid(-1, NULL, 0);
}
int main(int argc, char *argv[])
{signal(SIGCHLD, sigcb);pid_t pid fork();if(pid 0){ sleep(3);exit(0);}while(1){printf(------\n);sleep(1);}return 0;
}waitpid();有子进程退出返回值0没有子进程退出返回值0出错0 wait(-1, NULL, WNOHANG) -1等待任意一个子进程的退出 NULL返回值不关心 WNOHANG将接口设置为非阻塞 SIGPIPE管道所有读端被关闭则write出发异常对应的信号 SIGPIPE信号默认处理方式就是退出进程若不想退出则需要自定义/忽略 #includestdio.h
#includeunistd.h
#includestdlib.h
#includeerrno.h
#includefcntl.h
#includesys/stat.h
#includestring.h
#includesignal.hvoid sigcb(int no)
{printf(all pipe read is close\n);
}
int main(int argc, char *argv[])
{
//更换信号处理方式signal(SIGPIPE, sigcb);umask(0);char *fifo_name ./test.fifo;int ret mkfifo(fifo_name, 0664);if(ret 0 errno ! EEXIST){perror(mkfifo error);return -1;}int fd open(fifo_name, O_WRONLY);if(fd 0){perror(open error);return -1;}while(1){char buf[1024] {0};scanf(%s, buf);int ret write(fd, buf, strlen(buf));if(ret 0){perror(write error);return -1;}}close(fd);return 0;
} 关键字volatile 功能保持内存可见性–让cpu每次访问变量的时候都从内存中重新获取数据 目的防止编译器过度优化 可重入函数与不可重入函数 函数的重入在不同的执行流程中main、signal同时进入一个函数进行执行。 不可重入一个函数重入后有可能会造成数据二义或者逻辑混乱。 可重入一个函数重入后不会出现问题。 函数是否可重入的重点一个函数中是否对全局数据进行不受保护的非原子操作是-不可重入 //不可重入
#includestdio.h
#includeunistd.h
#includestdlib.h
#includesignal.hint a 0, b 0;int test()
{a;sleeo(1);b;printf(%d %d %d\n,a, b, ab);
}void sigcb(int no)
{test();
}int main(int argc, char *argv[])
{signal(SIGINT, sigcb);test();return 0;
}