您的位置:首页 > 新闻 > 资讯 > 石首seo排名_建立网站小程序_软文一般发布在哪些平台_网站的优化从哪里进行

石首seo排名_建立网站小程序_软文一般发布在哪些平台_网站的优化从哪里进行

2025/7/7 14:19:26 来源:https://blog.csdn.net/yugongbaocc/article/details/143243669  浏览:    关键词:石首seo排名_建立网站小程序_软文一般发布在哪些平台_网站的优化从哪里进行
石首seo排名_建立网站小程序_软文一般发布在哪些平台_网站的优化从哪里进行

信号量

本质是一个计数器,用来表示系统资源中,资源数量多少的问题。

公共资源:能被多个进程同时访问的资源。

访问没有被保护的资源,可能会出现数据不一致问题。

让不同进程看到同一个资源的目的是想通信。

为了解决进程具有独立性无法 ,让进程看到同一个资源,解决过程中,又引入了数据不一致问题。

未来被保护起来的公共资源,一般是临近资源。是共享的。

其他的进程中申请的资源大部分是独立资源。

资源是要被使用的,有进程对应的代码会访问这部分资源。

访问临近资源的代码是临界区,不访问临近资源的代码是非临界区。

要么不做,要做就做完:原子性。

为什么要信号量

想买电影票的座位号,当想要某种资源时,可以进行预订。

共享资源:作为一个整体使用,划分成为一个一个资源的子部分。

进程申请信号量成功 相当于预订了共享资源的一部分,可以访问这部分资源,否则就不可以,就可以实现保护共享资源的目的。

 

 当信号量是1 代表对共享资源整体访问,实现互斥功能。

所有IPC资源的第一个字段都是ipc_perm的结构,可以定义一个指针数组,不同对象,可以用相同指针数组存储。

 信号:

 

 信号不一定立即被处理,需要时间窗口。

 共识:信号是给进程发的。

进程如何识别信号?认识+动作。

进程是程序员编写的属性和逻辑的集合,是程序员编码完成的。

进程本身要有对信号的保存能力。

进程处理信号称为信号被捕捉。

 进程保存信号,保存在进程task_struct 结构体中。

发送信号本质是修改进程pcb中的信号位图。

 PCB是内核维护的数据结构对象。

PCB管理者是OS。

发送信号的方式都是通过OS向进程发送的信号。

kill 命令底层一定调用了对应的系统调用。

 

自定义信号操作: 

#include<iostream>
#include<unistd.h>
#include<signal.h>
using namespace std;void handler(int signo)
{cout<<"进程捕捉到一个信号,该信号是:"<<signo<<endl;
}
int main()
{signal(2,handler);while(true){cout<<"我是一个进程"<<getpid()<<endl;sleep(2);}
}

 

利用系统调用接口,模拟实现kill。

raise,给自己发任意的信号。 相当于kill(getpid(),3)。

 

 abort():给自己发送指定的信号。信号SIGABRT。

 异常捕捉:

#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;
void catchSig(int signo)
{cout<<"获取到一个信号,信号编号是"<<signo<<endl;
}
int main(int argc,char* argv[])
{int cnt=10;signal(SIGFPE,catchSig);while(cnt--){cout<<"cnt:"<<cnt<<endl;sleep(1);int a=10;a/=0;}
}

收到信号不一定引起进程退出,进程没有退出就有可能还被调度。

CPU内部寄存器只有一份,但是寄存器中内容属于进程上下文。 

状态寄存器cpu自己维护,不能更改它。

进程被切换时,就有无数次状态寄存器被保存和恢复的过程。 

每次恢复时,就让操作系统识别到了CPU内部状态寄存器的溢出标志位。

OS将 硬件问题转换为软件问题,向目标进程发信号,导致异常。

当程序捕获到 SIGFPE 信号并调用 catchSig 后,程序会恢复到触发信号的那一行(a/=0;),导致再次触发 SIGFPE 信号。因此 catchSig 函数会一直被调用,形成无限循环。

软件条件:类似与管道通信,读端关闭,写端也关闭。

软件条件闹钟:

#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;int main(int argc,char* argv[])
{alarm(1);int cnt=10;while(true){cout<<"cnt:"<<cnt++<<endl;}   
}

#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;
int cnt=0;
void catchSig(int signo)
{cout<<"获取到一个信号,信号编号是:"<<cnt<<endl;
}
int main(int argc,char* argv[])
{signal(SIGALRM,catchSig);alarm(1);while(true){// cout<<"cnt:"<<cnt++<<endl;cnt++;}   
}

一次性闹钟信号。 

catchSig函数中加入alarm闹钟。 

#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;
int cnt=0;
void catchSig(int signo)
{cout<<"获取到一个信号,信号编号是:"<<cnt<<endl;alarm(1);
}
int main(int argc,char* argv[])
{signal(SIGALRM,catchSig);alarm(1);while(true){// cout<<"cnt:"<<cnt++<<endl;cnt++;}   
}

 闹钟其实是用软件实现的

OS周期性检查闹钟,超时后,发送SIGALARM信号。

3:记录在进程PCB中

4: 系统程序员默认写好

5:更改目标进程PCB信号位图

核心转储

段错误是执行动作是Core 。核心转储。

 

 核心转储目的是支持调试。

直接定位到出错地方。 

#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;
int cnt=0;
void catchSig(int signo)
{cout<<"捕捉到一个异常,编号是:"<<signo<<endl;
}
int main(int argc,char* argv[])
{for(int i=1;i<=31;i++){signal(i,catchSig);}while(1){cout<<"这是一个进程,pid:"<<getpid()<<endl;sleep(1);}}

  kill -9 9号信号不能被捕捉。

实际执行信号处理动作叫信号递达。

信号从产生到递达之间的状态,交信号未决。

进程可以阻塞某个信号。

2个位图,一个数组分别代表未决,阻塞,处理状态。

 一个信号没有产生,并不妨碍它可以被阻塞。

信号产生时候不会被立即处理,而是在合适的时候,从内核态转为用户态时处理。

用户为了访问内核或硬件资源,必须通过系统调用完成访问。

实际执行系统调用的人是进程,身份其实是内核。

系统调用较费时间。尽量避免频繁进行系统调用。

凡是和当前进程相关的数据,都是当前进程的上下文数据。

CPU对应的CR3寄存器,为0是内核态,为3为用户态。
跳转到内核态,为了进行系统调用。

进程要执行系统调用,就从用户空间跳到内核空间后,调用内核级页表,执行系统调用。还需要从用户态变到内核态。

 

不会更改内核空间:

 pending为1代表收到,handler是处理方法。

handler处理信号方式,包括默认,忽略和自定义。

 所有语言 直接间接访问系统资源,IO,访问硬件 一定经过操作系统,经过操作系统一定有系统调用,有系统调用一定会切到系统内核。

 执行handler中的自定义处理方法,需要转为用户态。防止用户态程序利用内核态身份非法操作。

在用户态执行完handler函数后,需要返回到内核态,获取进程程序位置后,再返回到用户态进程继续执行。

自定义信号处理过程:

sigset_t

 信号集包括pending信号集和block信号集,block信号集一般叫信号屏蔽字。

默认情况,所有信号都是不被阻塞的,如果一个信号被屏蔽了,该信号不会被递达。

#include<iostream>
#include<signal.h>
#include<unistd.h>
using namespace std;#define BLOCK_SIGNAL 2
#define MAX_SIGNUM 31
static void show_pending(const sigset_t &pending)
{for(int signo=1;signo<=MAX_SIGNUM;signo++){if(sigismember(&pending,signo)){cout<<"1";}else cout<<"0";}cout<<endl;
} 
int main()
{sigset_t block,oblock,pending;//初始化sigemptyset(&block);sigemptyset(&oblock);sigemptyset(&pending);//添加要屏蔽的信号sigaddset(&block,BLOCK_SIGNAL);//开始屏蔽,设置进内核sigprocmask(SIG_SETMASK,&block,&oblock);//遍历打印pending信号集while(true){//初始化sigemptyset(&pending);//获取sigpending(&pending);//打印show_pending(pending);sleep(1);}
}

捕捉2号信号,并屏蔽。

用数组选择要屏蔽的信号。

#include<iostream>
#include<signal.h>
#include<unistd.h>
#include<vector>
using namespace std;#define BLOCK_SIGNAL 2
#define MAX_SIGNUM 31static vector<int> sigarr={2,4};
static void show_pending(const sigset_t &pending)
{for(int signo=1;signo<=MAX_SIGNUM;signo++){if(sigismember(&pending,signo)){cout<<"1";}else cout<<"0";}cout<<endl;
} 
int main()
{sigset_t block,oblock,pending;//初始化sigemptyset(&block);sigemptyset(&oblock);sigemptyset(&pending);//添加要屏蔽的信号sigaddset(&block,BLOCK_SIGNAL);//开始屏蔽,设置进内核for(const auto& sig:sigarr ){sigaddset(&block,sig);}sigprocmask(SIG_SETMASK,&block,&oblock);//遍历打印pending信号集while(true){//初始化sigemptyset(&pending);//获取sigpending(&pending);//打印show_pending(pending);cout<<"pid:"<<getpid()<<endl;sleep(1);}
}

恢复屏蔽:

#include<iostream>
#include<signal.h>
#include<unistd.h>
#include<vector>
using namespace std;#define BLOCK_SIGNAL 2
#define MAX_SIGNUM 31static vector<int> sigarr={2,4};
static void show_pending(const sigset_t &pending)
{for(int signo=1;signo<=MAX_SIGNUM;signo++){if(sigismember(&pending,signo)){cout<<"1";}else cout<<"0";}cout<<endl;
} 
int main()
{sigset_t block,oblock,pending;//初始化sigemptyset(&block);sigemptyset(&oblock);sigemptyset(&pending);//添加要屏蔽的信号sigaddset(&block,BLOCK_SIGNAL);//开始屏蔽,设置进内核for(const auto& sig:sigarr ){sigaddset(&block,sig);}sigprocmask(SIG_SETMASK,&block,&oblock);int cnt=15;//遍历打印pending信号集while(true){//初始化sigemptyset(&pending);//获取sigpending(&pending);//打印show_pending(pending);cout<<"pid:"<<getpid()<<endl;sleep(1);if(cnt--<=0){sigprocmask(SIG_SETMASK,&oblock,&block);cout<<"恢复对信号的屏蔽,不屏蔽任何信号"<<endl;}}
}

屏蔽恢复成功,但没有打印,因为是2信号,恢复后,进入内核态进程中止,进程不会返回用户态 

 自定义捕捉2号信号,验证恢复抵达成功。

#include<iostream>
#include<signal.h>
#include<unistd.h>
#include<vector>
using namespace std;#define BLOCK_SIGNAL 2
#define MAX_SIGNUM 31static vector<int> sigarr={2,4};
static void show_pending(const sigset_t &pending)
{for(int signo=1;signo<=MAX_SIGNUM;signo++){if(sigismember(&pending,signo)){cout<<"1";}else cout<<"0";}cout<<endl;
} 
void myhandler(int signo)
{cout<<signo<<"号信号已经被抵达"<<endl;
}
int main()
{sigset_t block,oblock,pending;//初始化sigemptyset(&block);sigemptyset(&oblock);sigemptyset(&pending);//添加要屏蔽的信号sigaddset(&block,BLOCK_SIGNAL);//开始屏蔽,设置进内核for(const auto& sig:sigarr ){   signal(sig,myhandler);sigaddset(&block,sig);}sigprocmask(SIG_SETMASK,&block,&oblock);int cnt=15;//遍历打印pending信号集while(true){//初始化sigemptyset(&pending);//获取sigpending(&pending);//打印show_pending(pending);cout<<"pid:"<<getpid()<<endl;sleep(1);if(cnt--<=0){sigprocmask(SIG_SETMASK,&oblock,&block);cout<<"恢复对信号的屏蔽,不屏蔽任何信号"<<endl;}}
}

 sigaction:

#include<iostream>
#include<signal.h>
#include<unistd.h>
#include<vector>
using namespace std;void handler(int signo)
{cout<<"get a signo"<<signo<<endl;
}
int main()
{struct sigaction act,oact;act.sa_handler=handler;act.sa_flags=0;sigemptyset(&act.sa_mask);sigaction(SIGINT,&act,&oact);while(true)sleep(1);return 0;
}

 当信号处理时间很长的情况。

#include<iostream>
#include<signal.h>
#include<unistd.h>
#include<vector>
using namespace std;void handler(int signo)
{cout<<"get a signo"<<signo<<"正在处理"<<"pid:"<<getpid()<<endl;sleep(15);
}
int main()
{struct sigaction act,oact;act.sa_handler=handler;act.sa_flags=0;sigemptyset(&act.sa_mask);sigaction(SIGINT,&act,&oact);while(true)sleep(1);return 0;
}

最终只处理了2个信号。 

 

 

 

 

上一个信号处理完,会自动解除对上一个信号和当前设置的信号的屏蔽。

 

 可重入函数

 

#include<iostream>
#include<signal.h>
#include<unistd.h>
#include<vector>
using namespace std;int quit=0;
void handler(int signo)
{cout<<signo<<"信号正在被捕捉"<<endl;cout<<"quit:"<<quit;quit=1;cout<<"->"<<quit<<endl;
}
int main()
{signal(2,handler);while(!quit)sleep(1);cout<<"我是正常退出的"<<endl;return 0;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com