当前位置: 首页 > news >正文

linux代码做网站服务公司荡神

linux代码做网站,服务公司荡神,西安广告公司,凡科网产品矩阵#x1f916;个人主页#xff1a;晚风相伴-CSDN博客 #x1f496;如果觉得内容对你有帮助的话#xff0c;还请给博主一键三连#xff08;点赞#x1f49c;、收藏#x1f9e1;、关注#x1f49a;#xff09;吧 #x1f64f;如果内容有误或者有写的不好的地方的话… 个人主页晚风相伴-CSDN博客 如果觉得内容对你有帮助的话还请给博主一键三连点赞、收藏、关注吧 如果内容有误或者有写的不好的地方的话还望指出谢谢 让我们共同进步 目录 前言 ✨信号的阻塞  信号的常见概念 在内核中的表示 ❔sigset_t类型 信号集操作函数 sigprocmask sigpending 示例代码 ✨信号的捕捉 理解信号捕捉的流程 sigaction ❔可重入函数​编辑 ❔volatile 前言  信号的时间线  在上一篇《信号之信号的产生》中已将信号产生讲明白了本篇就来讲讲信号的保存和处理吧。 ✨信号的阻塞  信号的常见概念 实际执行信号的处理动作称为信号递达Delivery信号从产生到递达之间的状态称为信号未决Pending进程可以选择阻塞Block某个信号。被阻塞的信号产生时将保持在未决状态直到进程解除对此信号的阻塞才执行递达的动作。 注意阻塞和忽略是不同的只要信号被阻塞就不会递达而忽略是在递达之后可选的一种处理动作。 在内核中的表示 信号在内核中的表示示意图 每个信号都有两个标志位分别表示阻塞和未决还有一个函数指针数组里面保存的是函数的地址表示处理动作。信号产生时操作系统在进程控制块PCB中设置该信号的未决标志由0-1直到信号递达后才清理该标志位由1-0。 例如在上面的图中 SIGHUP信号没有阻塞也没有产生当它递达时执行默认的处理动作。SIGINT产生了但是Block位图中是1表示它正在被阻塞着所以暂时不能递达虽然它的处理动作是忽略但在没有解除阻塞之前不能忽略这个信号因为进程仍有机会改变处理动作在解除阻塞之前。SIGQUIT信号没有产生但是Block位图中是1所以一旦产生了SIGQUIT信号将会被阻塞它的处理动作是用户自定义函数sighandler。 如果在进程解除对某信号的阻塞之前这个信号产生了多次Linux操作系统该如何处理呢 对于常规信号而言[1-31]操作系统会将它们在递达之前产生多次只计一次。也就是说即使这个信号在阻塞期间产生了多次当阻塞被解除并且信号能够传递给进程时进程只会收到一个这样的信号。 对于实时信号而言[34-64]它们在递达之前产生多次是可以排队的即多个相同的实时信号在阻塞期间产生会依次放在一个队列里当阻塞被解除时它们会按照产生的顺序依次递达给进程。 ❔sigset_t类型 每个信号就是由一个比特位来表示其状态非0即1。从上图可以看出在阻塞位图和未决位图中都是这样表示的所以它们可以用相同的数据类型sigset_t来进行存储sigset_t称为信号集。对于这个类型内部如何存储这些比特位的则依赖于系统实现用户并不需要关心这个类型可以表示每个信号“有效”或“无效”的状态在阻塞位图阻塞信号集中“有效”或“无效”就表示该信号是否被阻塞而在未决位图未决信号集中“有效”或“无效”就表示该信号是否产生。 注阻塞信号集也叫做当前进程的信号屏蔽字Signal Mask。 信号集操作函数 可以调用以下函数对sigset_t类型进行操作 #include signal.h int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigaddset(sigset_t *set, int signo); int sigdelset(sigset_t *set, int signo); int sigismember(sigset_t *set, int signo); sigemptyset函数初始化set所指向的信号集使其中所有的信号对应的比特位清0表示该信号集不包含任何有效信号。sigfillset函数初始化set所指向的信号集使其中所有的信号对应的比特位置1表示该信号集包含所有有效信号sigaddset函数在该信号集中添加某个有效信号sigdelset函数在该信号集中删除某个有效信号sigismember函数判断一个信号集的有效信号中是否包括了某个信号 前4个函数的返回值都是成功返回0失败返回-1。最后一个是若包含则返回1若不包含则返回0失败返回-1。   sigprocmask 该函数用于读取或者更改进程的信号屏蔽字阻塞信号集  如果oldset是非空指针则读取进程通过oldset参数传出的当前信号屏蔽字。如果set是非空指针则更改进程的信号屏蔽字参数how指示如何更改。如果oldset和set都是非空指针,则先将原来的信号屏蔽字备份到oldset里然后根据set和how参数更改信号屏蔽字。 下面是how参数的可选项 SIG_BLOCK将set指向的信号集添加到当前进程的信号屏蔽字中SIG_UNBLOCK将set指向的信号集从当前进程的信号屏蔽字中移除SIG_SETMASK设置当前信号屏蔽字为set所指向的值 如果调用sigprocmask解除了对当前若干个未决信号的阻塞则在sigprocmask返回前至少将其中一个信号递达。 sigpending 该函数用于读取当前进程的未决信号集 返回值成功成功返回0失败返回-1 示例代码 将2号信号阻塞掉并且不断的获取并打印当前进程的pending信号集如果我们向该进程发送一个2号信号我们就可以看到在pending信号集中一个比特位由0-1。  #include iostream #include stdlib.h #include signal.h #include unistd.h #include cassert #include sys/types.h #include sys/wait.h using namespace std;void handle(int signum) {cout 捕捉到信号: signum endl; }static void printPending(sigset_t pending) {for (int i 1; i 31; i){if (sigismember(pending, i))cout 1;elsecout 0;}cout endl; }int main() {//捕捉2号信号不让其退出signal(2, handle);// 1、定义信号集对象sigset_t bset, obset;sigset_t pending;// 2、初始化sigemptyset(bset);sigemptyset(obset);sigemptyset(pending);// 3、添加要屏蔽的信号sigaddset(bset, 2 /*SIGINT*/);// 4、设置set到内核中对应的进程内部int n sigprocmask(SIG_BLOCK, bset, obset);assert(n 0);(void)n;cout block 2号信号成功……, pid: getpid() endl;// 5、重复打印当前进程的pending信号集int count 0;while (true){// 获取pending信号集sigpending(pending);// 打印信号集printPending(pending);sleep(1);count;//count 20时解除对2号信号的阻塞if (count 20){n sigprocmask(SIG_SETMASK, obset, nullptr);assert(n 0);(void)n;cout 解除2号信号的block成功 endl;}}return 0; } 结果演示  如果我们将所有的信号都进行阻塞掉我们是不是就写了一个不会被异常或者用户杀掉的进程 这真的可以吗用下面的代码进行验证一下  static void printPending(sigset_t pending) {for (int i 1; i 31; i){if (sigismember(pending, i))cout 1;elsecout 0;}cout endl; }static void blockSig(int sig) {sigset_t bset;sigemptyset(bset);sigaddset(bset, sig);int n sigprocmask(SIG_BLOCK, bset, nullptr);assert(n 0);(void)n; }int main() {cout pid: getpid() endl;for (int sig 1; sig 31; sig){blockSig(sig);}sigset_t pending;while (true){// 获取pending信号集sigpending(pending);// 打印信号集printPending(pending);sleep(1);}return 0; }mykill.cc #include iostream #include string #include unistd.h #include stdlib.h #include signal.husing namespace std;void Usage(string proc) {cout Usage:\r\n\t proc processid endl; }int main(int argc, char *argv[]) {if (argc ! 2){Usage(argv[1]);exit(1);}int processid atoi(argv[1]);for (int i 1; i 31; i){if (i 9 || i 19)continue;kill(processid, i);cout kill - i endl;sleep(1);}kill(processid, 9);return 0; } 结果演示 其实在上面的代码中是屏蔽了9号信号和19号信号的如果你将9号信号放开这个进程立马就会被终止掉所以将所有信号阻塞掉还是可以将这个进程终止的——用9号信号。 19号信号是中止进程  ✨信号的捕捉 将所有的信号都捕捉那么这个进程是不是就不会被异常或者用户杀掉了呢 示例代码 void catchSig(int signum) {cout 获取一个信号: signum endl; }int main() {for (int i 1; i 31; i)signal(i, catchSig);while (true)sleep(1);return 0; } 结果演示  可见虽然我们自定义捕捉了所有信号但是9号信号还是有用的不会失效。  理解信号捕捉的流程 信号产生之后信号不是被立即处理而是在合适的时候进行处理。 内核态和用户态的概念 当一个进程执行系统调用而陷入内核代码中执行时则称其处于内核态 当一个进程在执行用户自己的代码时则称其处于用户态 怎么理解这个合适的时候呢 我们都知道信号的相关数据字段都是保存在进程PCB内部的而PCB是属于内核的范畴所以要检测这个信号是否未决是否产生一定是在内核状态进行检测的而进程大部分时间是在执行你写的代码而这所处的状态叫做用户态。所以当从内核态返回到用户态时就会对信号进行检测和处理。这就叫做合适的时候。 如何理解用户态和内核态之间的相互转换 在进程的地址空间中0-3GB是用户区3-4GB是内核区。 当进程处于用户态时在地址空间中的用户区的代码和数据通过用户级的页表映射到物理内存中CPU就能拿到代码和数据进行执行当进程处于内核态时在地址空间中的内核区的代码和数据用户内核级的页表映射到物理内存中CPU就能拿到代码和数据进行执行 注意内核级页表可以被每个进程所看到因为操作系统只有一个每个进程通过内核级页表映射到物理内存的同一块区域。 地址空间中的内核区和用户区之间的转换是通过系统调用和上下文切换来实现的。 例如你在你的代码中使用了系统调用接口open它就会直接在地址空间中由用户区跳转到内核区然后再内核区通过内核级页表将代码和数据映射到物理内存上。 注CPU可以通过寄存器里的值就能知道当前进程是处于用户态还是内核态 当然内核也是可以执行用户的代码的但是内核不愿意也不想这样干因为如果这样干很可能导致内核中的数据和代码被用户给修改了。 信号捕捉的流程图 假设用户自定义的信号处理函数sighandler进程当前正在执行用户的代码这时执行到某条指令时发生了中断用户态切换到了内核态并保存当前进程的上下文。内核态将中断处理完后需要返回到用户态在返回之前先检查一下是否有信号需要递达 如有则要对信号进行处理如果信号的处理动作是用户自定义的 那么内核态就要返回到用户态执行sighandler函数sighandler和主函数使用不同的堆栈空间它们之间不存在调用和被调用的关系是两个独立的控制流程sighandler函数处理完后进程又再次返回到内核态如果没有新的信号需要递达了那么就需要从内核态返回到用户态并且恢复上下文继续从主逻辑向下执行。 可以简化成下面这幅图 sigaction sigaction函数可以读取和修改与指定信号相关联的处理动作。和signal作用类似 参数 sig指定信号的编号若act指针非空则根据act修改该信号的处理动作。若oact指针非空则通过oact传出该信号原来的处理动作 返回值成功则返回0失败则返回-1。 说明 sa_handler是一个回调函数被系统所调用。 当某个信号的处理函数被调用时内核自动将当前信号加入进程的信号屏蔽字当信号处理函数返回时自动恢复原来的信号屏蔽字这样就保证了在处理某个信号时,如果这种信号再次产生那么它会被阻塞到当前处理结束为止。 如果在调用信号处理函数时除了当前信号被自动屏蔽之外还希望自动屏蔽另外一些信号则用sa_mask字段说明这些需要额外屏蔽的信号当信号处理函数返回时自动恢复原来的信号屏蔽字。 sa_flags字段包含一些选项,本篇的代码把sa_flags设为0sa_sigaction是实时信号的处理函数这里不做讨论。 示例代码 static void printPending(sigset_t pending) {for (int i 1; i 31; i){if (sigismember(pending, i))cout 1;elsecout 0;}cout endl; }void handler(int signum) {cout 捕捉到一个信号: signum endl;int count 20;sigset_t pending;while (true){// 获取pending信号集sigpending(pending);// 打印信号集printPending(pending);count--;if (!count)break;sleep(1);} }int main() {cout pid: getpid() endl;struct sigaction act, oact;act.sa_flags 0;sigemptyset(act.sa_mask);sigaddset(act.sa_mask, 3);sigaddset(act.sa_mask, 4);sigaddset(act.sa_mask, 5);sigaddset(act.sa_mask, 6);act.sa_handler handler;sigaction(2, act, oact);cout default action: (int)(oact.sa_handler) endl;while (true)sleep(1); } 结果演示 ❔可重入函数 例如在图中的循环单链表 在主函数中调用insert函数向一个链表的头节点插入节点node1插入操作分为两步刚做完第一步时因为硬件中断使进程切换到内核当内核态会到用户态之前检查到有信号需要处理于是切换到自定义的信号处理函数信号处理函数中也调用了insert函数向同一个链表的头节点中插入node2插入操作的两步都完成了之后信号处理函数返回到内核态再次返回到用户态后就从主函数调用的insert函数中继续向下执行先前只做完了第一步就被打断了现在继续做插入操作的第二步但是在自定义的信号处理函数中已经插入了node2了node2作为新的头结点node1在完成剩下的一步时就会导致node2节点丢失导致内存泄漏等问题。 所以一个函数在一个特定的时间段内被多个执行流重复进入如果该函数被重复进入不会导致问题那么就叫做可重入函数否则就叫做不可重入函数 如果一个函数符合以下条件之一则是不可重入的 调用了malloc或free因为malloc也是用全局链表来管理堆的。调用了标准I/O库函数。标准的I/O库的很多实现都以不可重入的方式使用全局数据结构。 ❔volatile 示例代码  int flag 0;void changeFlag(int signum) {(void)signum;cout change flag: flag;flag 1;cout - flag endl; }int main() {signal(2, changeFlag);while (!flag);cout 进程正常退出后: flag endl;return 0; } 没给编译器加优化前  结果演示 给编译器加了优化后 结果演示 导致这样的结果的原因 在没加优化之前CPU是正常从我们的内存中读取flag的值的在flag由0-1后CPU读取到了1就直接让进程终止掉了。在加了优化之后CPU在看了main函数中没有对flag进行修改的相关语句所以CPU就不在从内存中读取flag的值了而是从自己的寄存器中读取比如说edx寄存器 所以CPU一直读取到的flag是0也就不会让进程终止掉了。 加了优化并且加了volatitle后 结果演示 volatitle作用保持内存的可见性告知编译器被该关键字修饰的变量不允许被优化对该变量的任何操作都必须在真实的内存中进行操作。
http://www.hkea.cn/news/14296007/

相关文章:

  • 长沙行业网站建设ps设计一个手机ui界面
  • 海外建站推广网站编程培训
  • 北京国税局网站做票种核定时呼叫中心系统厂家排名
  • 全球建筑网站江苏网页设计报价
  • 教你做企业网站做一个企业网站设计
  • 免费网站友情链接登录
  • 哪有做奇石网站悬停提示 wordpress
  • 上海网站制作电话制作自己的app多少钱
  • 做网站闵行个人域名注册流程
  • 网站建设贰金手指下拉壹玖深圳市建设工程质量检测中心网站
  • 虹口广州网站建设旅游业网站建设方案特点
  • 展示网站动画怎么做的seo教育培训机构
  • 常见的网站空间重庆网站seo按天计费
  • 如何设置个人网站visual studio做网站
  • 广西柳州网站制作公司网站推广的网站
  • 临沂企业建站系统外贸英语 网站
  • 中山市城乡建设局网站个体工商户经营范围网站开发
  • 韩国网站建设设置wordpress上传文件大小
  • 装潢公司网站设计与制作嘉峪关市建设局公示公告网站
  • 网站建设是指什么东莞玩具加工东莞网站建设
  • xp花生壳做网站网站没备案怎么做淘宝客
  • 昆明做网站建设的公司哪家好画画外包网站
  • 查看网站是由什么开源做的无锡定制网站制作公司
  • 正规品牌网站设计一般网站维护需要做什么
  • 淘宝客网站怎么做产品设计五个流程
  • 装饰网站建设的方案app推广联盟平台
  • 做网站主流用什么语言贵阳网站建设平台
  • 陕西网站建设哪家专业百度上能收到的企业名称网站怎么做
  • 官方网站建设银行年利息是多少cps推广是什么意思
  • 网站使用什么数据库公司网站建设会计处理