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

国外比较好的建筑设计网站wordpress 主题制作教程

国外比较好的建筑设计网站,wordpress 主题制作教程,个人可以做商城网站,常州网络网站建设信号的概念 知识补充 信号是进程之间事件异步通知的一种方式#xff0c;是一种软中断。 标准信号#xff1a;编号为1-31之间都是标准信号#xff0c;这些都是预定义信号#xff0c;用于通知进程发生的各种事件。实时信号#xff1a;编号从32开始起均是实时信号…信号的概念 知识补充 信号是进程之间事件异步通知的一种方式是一种软中断。 标准信号编号为1-31之间都是标准信号这些都是预定义信号用于通知进程发生的各种事件。实时信号编号从32开始起均是实时信号与标准信号相对应。   当OS收到相关信号时要通知相应的进程但是当前进程可能正在做着别的事情没空处理这个信号。此时就要记录下来该信号那么如何记录呢普通信号的编号是从 1 - 31并没有0号信号我们将0号位置作为位图来记录信号。所以发送信号的本质就是OS修改目标进程的PCB中的信号位图0 -1。 发送信号的只能是OS因为task_struct的管理者是OS。  信号的处理方式 忽略信号进程可以选择忽略某些信号即不对该信号进行任何处理。捕捉信号自定义处理进程可以注册一个信号处理函数来捕捉特定的信号并在接收到该信号时执行相应的处理逻辑。默认处理如果进程没有注册信号处理函数且没有选择忽略信号则系统会按照默认的处理方式来处理该信号。通常情况下默认处理方式会导致进程终止或停止。 前台进程与后台进程 信号的产生 键盘产生信号 在信号概念模块 我们使用键盘 ctrl c 组合键触发的就是2号信号(SIGINT)。 signal函数 signum要处理的信号类型它是一个整数对应于某个具体的信号。handler函数指针类型用来接收自定义的函数。执行调用的函数就是执行自定义的操作。 // 修改2号信号的默认处理动作 void Handler(int signo) {std::cout Get a signal, signal number is : signo std::endl; } int main() {// 如果没有产生2号信号则Handler将不被调用signal(SIGINT, Handler);while(1){std::cout hello world std::endl;sleep(1);}return 0; } 在所有的普通信号里面除了9号信号外所有信号都可以被signal函数捕捉 调用系统指令发送信号 指令底层使用的也是系统调用(下面的kill函数)  使用函数产生信号  kill函数(系统调用) // 使用kill函数模拟实现一个kill命令 #include iostream #include cstdlib #include sys/types.h #include signal.h #include unistd.hint main(int argc, char *argv[]) {if(argc ! 3){std::cerr Usage: argv[0] signum pid std::endl;return 1;}int signum std::stoi(argv[1]);pid_t id std::stoi(argv[2]);int n ::kill(id, signum);if(n 0){perror(kill);exit(2);}exit(0); } 运行结果  raise函数(系统调用) raise 函数给当前进程发送指定的信号(自己给自己发信号)。 参数 sig要发送的信号编号。如果该参数为SIGKILL信号编号为9则该进程会自杀。返回值 如果成功返回0。如果失败返回-1并设置errno以指示错误。 // 3秒后该进程自杀 int main(int argc, char *argv[]) {int cnt 3;while(1){std::cout alive std::endl;cnt--;if(cnt 0) raise(9);sleep(1);}return 0; } 实际上是调用kill函数kill(getpid(), signo) abort函数(系统调用) abort(); abort是用来终止进程的实际上就是自己给自己发送6号信号。实际上也是调用kill函数kill(getpid(), 6) 软件条件产生信号 alarm函数 调用 alarm 函数可以设定一个闹钟,也就是告诉内核在 seconds 秒之后给当前进程发SIGALRM 信号该信号的默认处理动作是终止当前进程。 函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。 // 统计我的服务器1S可以将计数器累加多少 int number 0; void die(int signumber) {printf(get a sig : %d, count : %d\n, signumber, number);exit(0); } int main(int argc, char *argv[]) { alarm(1); // 我自己会在1S之后收到一个SIGALRM信号(14号信号)signal(SIGALRM, die);while (true) number;return 0 } 闹钟的功能 当调用alarm(seconds)时内核会启动一个定时器当定时器到期时内核会向调用进程发送一个SIGALRM信号。当操作系统中多处要用到alarm的时候OS就会借助最小堆进行判断谁的定时器到期就向谁发送SIGALRM信号。如果在定时器到期之前再次调用alarm之前的定时器会被取消新的定时器开始计时。如果进程在定时器到期之前终止定时器也会被取消。 如果之前已经设置了一个定时器alarm会返回之前定时器剩余的时间以秒为单位。如果没有之前设置的定时器返回0。 int n alarm(0); // 0:取消闹钟 Demo代码 // 设置重复闹钟 #include iostream #include string #include functional #include vector #include unistd.h #include signal.husing func_t std::functionvoid();int gcount 0; std::vectorfunc_t gfuncs;void hanlder(int signo) {for(auto f : gfuncs) { f(); }std::cout gcount : gcount std::endl;alarm(1); }int main() {gfuncs.push_back([](){ std::cout 我是一个内核刷新操作 std::endl; });gfuncs.push_back([](){ std::cout 我是一个检测进程时间片的操作如果时间片到了我会切换进程 std::endl; });gfuncs.push_back([](){ std::cout 我是一个内存管理操作定期清理操作系统内部的内存碎片 std::endl; });alarm(1); // 一次性的闹钟超时alarm会自动被取消signal(SIGALRM, hanlder);while (true){pause();std::cout 我醒来了... std::endl;gcount;} } 异常产生信号 // 空指针 / 除0 操作引发异常产生信号 int main() {int *p nullptr;*p 100; // 对空指针解引用// int a 10;// a / 0; // 除0while (true){std::cout hello bit, pid: getpid() std::endl;sleep(1);} } 运行结果  Core VS Term termtermination 定义term信号的动作是直接终止进程。当进程接收到term信号时它会立即停止运行并且不会生成core dump文件。用途通常用于正常终止进程或者在进程已经处于异常状态时强制终止它以避免进一步的资源占用或系统不稳定。 core 定义core信号的动作同样是终止进程但与term不同的是core在终止进程的同时会生成core dump文件。这个文件包含了进程在内存中的核心数据主要是与调试有关的数据如变量值、函数调用栈等。core dump文件当进程因为接收到core信号而异常退出时它会将内存中的核心数据转储到磁盘上形成core dump文件。这个文件对我们程序员来说非常有用因为它可以帮助定位程序为什么退出以及是在哪一行退出的。通过分析core dump文件程序员可以找出导致程序崩溃的原因并修复相应的bug。用途主要用于调试和错误分析。程序员可以利用core dump文件来重现程序崩溃时的场景以便更好地理解和修复问题。此外core dump文件还可以用于检查内存泄漏等问题。 总结 进程终止方式term信号直接终止进程不生成core dump文件而core信号在终止进程的同时生成core dump文件。调试和错误分析term信号不提供额外的调试信息而core信号通过生成的core dump文件为程序员提供了丰富的调试信息有助于定位和解决程序中的问题。 信号捕捉的三种方式 默认捕捉 ::signal(2, handler); // 自定义捕捉 忽略捕捉 ::signal(2, SIG_IGN); // ignore: 忽略本身就是一种信号捕捉的方法动作是忽略 自定义捕捉 ::signal(2, SIG_DFL); // default: 默认。 信号的保存 补充概念 实际执行信号的处理动作称为信号递达(Delivery)信号从产生到递达之间的状态称为信号未决(Pending)。进程可以选择阻塞 (Block )某个信号。被阻塞的信号产生时将保持在未决状态直到进程解除对此信号的阻塞,才执行递达的动作.阻塞和忽略是不同的只要信号被阻塞就不会递达而忽略是在递达之后可选的一种处理动作。 信号在内核中的表示 相关函数接口 sigset_t: sigset_t称为信号集(一个位图)。信号集用于表示每个信号的状态即该信号是有效的(未被阻塞)还是无效的被阻塞。通过使用sigset_t类型的变量可以进行信号集的操作例如添加信号、删除信号、检查信号是否存在等操作。阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask)这里的“屏蔽”是阻塞而不是忽略。 信号集操作函数 #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(const sigset_t *set, int signo); 函数 sigemptyset 初始化set所指向的信号集使其中所有信号的对应bit清零表示该信号集不包含任何有效信号。函数 sigfillset 初始化set所指向的信号集使其中所有信号的对应bit置位表示该信号集的有效信号包括系统支持的所有信号。注意在使用sigset_ t类型的变量之前,一定要调用 sigemptyset 或 sigfillset 做初始化使信号集处于确定的状态。初始化sigset_t变量之后就可以在调用 sigaddset 和 sigdelset 在该信号集中添加或删除某种有效信号。 上面四个函数都是成功返回0出错返回-1。而sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含 某种 信号若包含则返回1不包含则返回0出错返回-1。 sigprocmask函数 sigprocmask函数可以 读取或更改 进程的信号屏蔽字(阻塞信号集block表)。 #include signal.h int sigprocmask(int how, const sigset_t *set, sigset_t *oset); // 返回值:若成功则为0,若出错则为-1 how指定对信号屏蔽集的操作方式有以下几种方式 SIG_BLOCK将set所指向的信号集中包含的信号添加到当前的信号屏蔽集中即信号屏蔽集和set信号集进行逻辑或操作。SIG_UNBLOCK将set所指向的信号集中包含的信号从当前的信号屏蔽集中删除即信号屏蔽集和set信号集的补集进行逻辑与操作。SIG_SETMASK将set的值设定为新的进程信号屏蔽集即set直接对信号屏蔽集进行了赋值操作。 set指向一个sigset_t类型的指针表示需要修改的信号集合。如果只想读取当前的屏蔽值而不进行修改可以将其置为NULL。 oldset指向一个sigset_t类型的指针用于存储修改前的内核阻塞信号集。如果不关心旧的信号屏蔽集可以传递NULL。 如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则 更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号 屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。 sigpending函数 sigpending函数用于 读取 当前进程的未决信号集(pending表)通过set参数传出。 #include signal.h int sigpending(sigset_t *set); // 调⽤成功则返回0,出错则返回-1 ps. signal函数修改handler表。 Demo代码 结合上面介绍的相关函数做一个Demo我们把2号信号block对应的位图置为1即将2号信号屏蔽掉此时我们给当前进程发送2号信号因为2号信号已经被屏蔽了所以2号信号永远不会递达之后我们不断的获取当前进程的pending表我们就能肉眼看见2号信号被pending的效果验证 1. 对2号信号的屏蔽  // 1.屏蔽2号信号 int main() {sigset_t block_set,old_set;sigemptyset(block_set);sigemptyset(old_set);// 1.1 添加SIGINT信号编号为2sigaddset(block_set,SIGINT);// 1.2 设置进入进程的Block表中// 真正的修改当前进行的内核的block表完成了对2号信号的屏蔽sigprocmask(SIG_BLOCK, block_set, old_set); while(true) sleep(1); } 2. 打印pending表并给该进程发送2号信号 void PrintPending(sigset_t pending) {std::cout curr process[ getpid() ]pending: ;for (int signo 31; signo 1; signo--){if (sigismember(pending, signo))//如果存在就返回1std::cout 1;else std::cout 0;}std::cout \n; }int main() {// 1.屏蔽2号信号sigset_t block_set,old_set;sigemptyset(block_set);sigemptyset(old_set);// 1.1 添加SIGINT信号编号为2sigaddset(block_set,SIGINT);// 1.2 设置进入进程的Block表中// 真正的修改当前进行的内核的block表完成了对2号信号的屏蔽sigprocmask(SIG_BLOCK, block_set, old_set); while(true) {//2.获取当前进程的pending信号集sigset_t pending;sigpending(pending);//3.打印pending信号集PrintfPending(pending);sleep(1);} } 我们将2号信号屏蔽后打印pending表首先打印出来的是31个0当我们按下ctrl c组合键后向该进程发送2号信号该进程没有被终止因为信号产生之后pending表2号位置由 0 变 1 又因为2号信号被屏蔽即永远不会递达所以我们可以看到panding表发生变化但进程不会被终止如果不解除屏蔽pending表2号位置永远都是1 3. 解除屏蔽打印pending表 void PrintPending(sigset_t pending) {std::cout curr process[ getpid() ]pending: ;for (int signo 31; signo 1; signo--){if (sigismember(pending, signo))//如果存在就返回1std::cout 1;else std::cout 0;}std::cout \n; } int cnt 0; int main() {// 解除屏蔽后2号信号正常递达在该进程中就会直接退出// 我们还想看到后续的现象所以使用signal忽略掉此信号::signal(2, SIG_IGN);// 1.屏蔽2号信号sigset_t block_set,old_set;sigemptyset(block_set);sigemptyset(old_set);// 1.1 添加SIGINT信号编号为2sigaddset(block_set,SIGINT);// 1.2 设置进入进程的Block表中// 真正的修改当前进行的内核的block表完成了对2号信号的屏蔽sigprocmask(SIG_BLOCK, block_set, old_set); while(true) {//2.获取当前进程的pending信号集sigset_t pending;sigpending(pending);//3.打印pending信号集PrintfPending(pending);sleep(1);cnt;// 4. 解除屏蔽if(cnt 5){std::cout 解除对2号信号的屏蔽 std::endl;sigprocmask(SIG_SETMASK, oblock, nullptr);}} } 通过运行结果我们可以发现一开始panding表全为0当我们按下ctrl c组合键后变为1。几秒后解除屏蔽又变为0。 信号的处理 当产生一个信号进程需要将改进好保存起来在合适的时候在执行该信号。那么这个合适的时候是什么时候呢其实是在进程在从 内核态 切换回 用户态 的时候检测当前进程的pending表 block表决定是否处理handler表处理信号 用户态内核态 操作系统是怎样运行的 硬件中断 中断向量表就是操作系统的一部分启动就加载到内存中了通过外部硬件中断操作系统就不需要对外设进行任何周期性的检测或者轮询由外部设备触发的中断系统运行流程叫做硬件中断 时钟中断 进程可以在操作系统的指挥下被调度被执行那么操作系统自己被谁指挥被谁推动执行呢答案是时钟中断在每一个系统中都有一个叫做 “时钟源” 的外设在极短的时间内一直向CPU发送中断请求进而CPU获取中断号查中断向量表OS就不断的进行中断服务只不过在现代计算机中 “时钟源” 都被集成在CPU内部(主频)因为在外部时间上太慢了空间上一直占用中断控制器。 基于上面的理解操作系统是什么操作系统就是基于中断向量表进行工作的 操作系统自己不做任何事情需要什么功能就向中断向量表里面添加方法即可。操作系统的本质就是一个死循环 什么是时间片时间片就是一个int count;如果时间片没有减为0就什么也不做如果减为0就进行进程切换 软中断 软中断则是由软件即系统中的某个进程或程序触发的常用于系统调用、异常处理以及中断服务的下半部处理。 为了让操作系统支持进行系统调用CPU设计了对应的汇编指令(int 或者 syscall)可以让CPU内部触发中断逻辑即软中断。 系统调用的过程其实就是先int 0x80、syscall陷入内核本质就是触发软中断CPU就会自动执行系统调用的处理方法而这个方法会根据系统调用号(数组下标)自动查表执行对应的方法。 CPU内部的软中断比如int 0x80或者syscallCPU内部没有错误我们叫做 陷阱。CPU内部的软中断比如除零/野指针等CPU内部出现错误 我们叫做 异常。 信号捕捉的操作 sigaction函数 参数说明 signum指定要设置或获取处理程序的信号编号。可以指定SIGKILL和SIGSTOP以外的所有信号。act指向sigaction结构体的指针用于指定新的信号处理方式。如果此参数非空则根据此参数修改信号的处理动作。oldact如果非空则通过此参数传出该信号原来的处理动作。如果你想恢复以前的方式此参数就是保存之前的操作方式 Demo样例代码 //act指向的sigaction结构体(我们只考虑第一个和第三个参数) //struct sigaction { // void (*sa_handler)(int); // 指向信号处理函数的指针接收信号编号作为参数 // void (*sa_sigaction)(int, siginfo_t *, void *); // 另一个信号处理函数指针支持更丰富的信号信息 // sigset_t sa_mask; // 设置在处理该信号时暂时屏蔽的信号集 // int sa_flags; // 指定信号处理的其他相关操作一般为0 // void (*sa_restorer)(void); // 已废弃不用关心 //};void handler(int signo) {std::cout get a sig: signo std::endl;exit(1); } int main() {// 定义struct sigaction结构体对象struct sigaction act, oact;// 获得结构体中的方法act.sa_handler handler;// 调用sigaction函数::sigaction(2, act, oact);while (true)pause();return 0; }注意如果在处理信号期间又来了一个该信号需要处理。这时OS会自动把对应信号的block位设置为1(阻塞住该信号)等信号处理完成OS又会自动把对应信号的block位由1置为0。 // 打印Block表 void PirintBLock() {sigset_t set, oset;// 将信号集set、oset全部位置为0sigemptyset(set);sigemptyset(oset);sigprocmask(SIG_BLOCK, set, oset);std::cout block: ;for (int signo 31; signo 0; signo--){if (sigismember(oset, signo)) std::cout 1;else std::cout 0;}std::cout std::endl; } void handler(int signo) {static int cnt 0;cnt;while (true){std::cout get a sig: signo , cnt: cnt std::endl;PirintBLock();sleep(1);}exit(1); } int main() {struct sigaction act, oact;act.sa_handler handler;::sigaction(2, act, oact);while (true){PirintBLock();pause();} } 其他问题 volatile关键字 #include stdio.h #include signal.h #include unistd.hint flag 0; void change(int signo) // 信号捕捉的执行流 {flag 1;printf(change flag 0-1, getpid: %d\n, getpid()); }int main() {printf(I am main process, pid is : %d\n, getpid());signal(2, change);while(!flag); // 主执行流--- flag我们没有做任何修改printf(我是正常退出的!\n); } 上面代码中共有两个执行流但它们同属一个进程。 当我们使用 signal 捕捉了2号信号进而执行了change自定义方法后全局变量flag就被更改为1再回到main函数其里面的while循环条件不成立就会停止执行因为CPU在执行while循环的时候是实时的从内存中取flag来进行比较的所以程序正常退出。 我们再次运行并在编译时进行优化优化会让CPU保存 之前在内存中取的flag的值即取flag在内存中最开始的值这就会导致虽然flag的值发生了变化但是CPU一直取得都是flag最开始的值就导致while循环无法结束。 如果将上面代码中的int flag 0;改为 volatile int flag 0; // 易变关键字 再运行。 我们发现可以正常退出了。volatile关键字表示保持flag变量的内存可见性即确保变量每次访问时都直接从内存中读取。(ps. 所有的关键字都是给编译器看的) SIGCHLD信号(17号信号) 子进程退出时不是静悄悄的退出的会给父进程发送 SIGCHLD信号。 通过man 7 signal可以查到SIGCHLD信号的默认处理动作是Ign(忽略) Signal Standard Action Comment SIGCHLD P1990 Ign Child stopped or terminated父进程可以自定义SIGCHLD信号的处理函数这样父进程只需专心处理自己的工作,不必关心⼦进程了子进程终止时会通知父进程父进程在信号处理函数中调用wait清理子进程即可。 // 验证子进程退出给父进程发送SIGCHLD父进程通过该信号回收子进程 void handler(int signo) {std::cout get a sig: signo I am : getpid() std::endl;// 等待进程的pid为-1时表示回收最近退出的子进程pid_t rid ::waitpid(-1, nullptr, 0);if(rid 0){std::cout 子进程退出了,回收成功,child id: rid std::endl;} } int main() {// 捕捉并自定义动作::signal(SIGCHLD, handler);if(fork() 0){sleep(3);std::cout 子进程退出 std::endl;// 子进程exit(0);}while(1) sleep(1);return 0; } signal(SIGCHLD, SIG_IGN); 也可以通过上面一行代码来实现父进程对子进程的回收。这行代码的作用是设置信号处理函数以便当子进程结束时即发送SIGCHLD信号给父进程时父进程忽略这个信号。通常当子进程结束时父进程需要处理这个信号以回收子进程的资源但在这里通过将其设置为SIG_IGN父进程选择忽略这个信号这意味着子进程的资源将由操作系统自动回收这通常被称为“僵尸进程”的避免尽管在这种情况下由于子进程正常退出并设置了退出码它实际上不会成为僵尸进程因为操作系统会注意到并清理它。 注意如果你不关心子进程的退出信息就可以使用这种方法否则还是要进行等待。
http://www.tj-hxxt.cn/news/133630.html

相关文章:

  • 重庆网站推广外包静态网站开发环境
  • 手机网站用什么后台视频类网站如何做缓存
  • 网站建设顾问站建建视频网站模板
  • 数字博物馆网站建设内容学校网站建设成功案例
  • 成品ppt的网站免费观看制作网页链接的软件
  • 章丘环保网站建设 中企动力云南人才招聘网
  • 哪个网站做兼职可以赚钱平面设计主要学什么哪些软件
  • 怎样php网站建设怎样开网店详细教程
  • 大学代作作业的网站成都高端网站制作公司
  • 自己做的宫崎骏动漫网站如何做网站logo
  • 网站建设格式合同网站建设 业务
  • WordPress网站仿制做网站怎么在国外服务器租用
  • 网站建设怎么弄设计新颖的网站建站
  • php自己写框架做网站wordpress搭建下载站
  • 中山企业网站推广公司购物平台网站建设流程
  • 网站宣传策划方案网站开发项目策划
  • 二级域名 电子商务网站推广方案推广方法和技巧
  • 网站图片修改怎么用html做个人的网页
  • 网站改版 合同做签证宾馆订单用啥网站
  • 专注做农产品的网站wordpress会员认证
  • 山东定制版网站建设公司电子商务网站建设需求
  • 静态网页模板素材重庆百度seo排名优化软件
  • 龙岩网站建设加盟wordpress文章编辑软件
  • 做啤酒行业的网站设计外贸网站
  • 平凉市网站建设制作企业网站改版的意义
  • 推广软件赚钱违法吗山西网络营销推广seo
  • 陕西培训网站建设网站建设程序员
  • 1688网站简介智慧团建网站几点关闭
  • 如何自己做网站界面可以放钓鱼网站的免费空间
  • 网站案例代码辽宁建设工程信息网诚信库官网