做网站中网页的大小,万网标准网站销售手册,国际新闻界官网,成都网站建设有名的#x1f436;博主主页#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️#x1f525;专栏系列#xff1a;线性代数#xff0c;C初学者入门训练#xff0c;题解C#xff0c;C的使用文章#xff0c;「初学」C#xff0c;linux #x1f525;座右铭#xff1a;“不要等到什么都没有了… 博主主页ᰔᩚ. 一怀明月ꦿ ❤️专栏系列线性代数C初学者入门训练题解CC的使用文章「初学」Clinux 座右铭“不要等到什么都没有了才下定决心去做” 大家觉不错的话就恳求大家点点关注点点小爱心指点指点 目录 信号量
如何理解信号量
信号
信号的概念 信号的产生
singal
信号种类
0-31是普通信号
通过系统调用实现信号产生
Kill系统调用
raise
abort
异常发送信号
软件条件产生异常
alarm 信号量 信号量的本质是一把“计数器” 多个执行流进程看到的同一份资源其实就是公共资源由os提供的如果并发访问同一份资源会导致数据不一致的问题我们就应该对公共资源进行保护可以利用可同步和互斥在多线程的时候着重理解来解决。 互斥任何时刻只允许一个执行流进程访问公共资源加锁实现的 同步多个执行流进程执行的时候按照一定顺序执行条件变量实现 被保护起来的公共资源临界资源 访问临界资源的代码临界区 非临界资源 非临界区 维护临界资源其实就是在维护临界区 原子性只有2两种状态要么做要么不做 如何理解信号量 信号量表示资源数目的计数器每一个执行流进程想要访问公共资源内的某一份资源不应该让执行流进程直接访问而是先申请信号量资源其实就是先对信号量计数器进行--操作。本质上--就完成了对资源的预定机制 如果申请不成功我们的执行流进程被阻塞等到申请成功 申请信号量资源是-- 释放信号量资源是 二元信号量起到了互斥的效果因为信号量资源只有一份互斥锁 1.意味着每一个进程都先看到同一个信号量资源
2.信号量本质也是公共资源
3.单个信号量
struct sem
{Int count;Task_strct* wait_queue
} 信号 信号的概念 生活中的信号 红绿灯、下课铃声、狼烟、闹钟等等 我进程为什么知道信号呢肯定我进程之前就了解过信号 信号没有产生的时候其实我进程已经能够知道怎么处理这个信号 信号的到来我进程并清楚具体什么时候信号到来相对于我进程正在做的工作是异步产生的 信号产生了我进程不一定立即处理它而是我进程在合理的时候处理 我进程必须要一种能力将已经到来的信号进行暂时保存 什么叫做信号 信号是向目标进程发送通知消息的一种机制 异步 简单理解在同一个时间下一个进程做一个事情的时候另一个进程也在做事情 信号的产生 进程在运行的时候例 前台运行./myprocess 后台运行./myprocess 前台进程只能有一个后台进程可以有多个 在 Linux 终端中jobs 是一个命令用于显示当前终端会话中正在运行的作业进程。当你在终端上启动一个作业时它将在前台或后台运行。使用 jobs 命令可以列出这些作业的状态和编号。 以下是一些与 jobs 命令相关的常用操作 1. jobs列出当前终端会话中正在运行的进程。每个进程都有一个编号并且会显示进程状态运行中、停止等。 2. bg job编号将一个停止的进程切换到后台运行。job编号 是通过 jobs 命令列出的进程编号。 3. fg job编号将一个在后台运行的进程切换到前台运行。job编号 是通过 jobs 命令列出的进程编号。 4. CtrlZ将当前正在前台运行的进程暂停并将其放置到后台。可以使用 jobs 命令查看该进程的状态和编号。 5. CtrlC终止当前正在前台运行的进程不会终止shell。 OS怎么知道键盘有数据输入呢 通过硬件向CPU发送中断号CPU就能够知道键盘有数据输入 信号本质其实就是用软件来模拟中断的行为 键盘有两种数据输入 1.普通数据 2.组合键的输入^C、^Z等 信号在合适的时候处理 1.默认行为例如生活中红灯时需要我们等一等 2.忽略行为 3.自定义的例如在等红灯的时候唱歌 singal 在 Linux 中signal() 函数用于注册信号处理函数 该函数原型如下 #include signal.h
void (*signal(int signum, void (*handler)(int)))(int);
* signum 表示要捕获的信号编号比如 SIGINT、SIGTERM 等。
* handler 是一个指向函数的指针该函数负责处理接收到的信号。
signal() 函数的返回类型是一个函数指针指向当前信号的处理函数。在调用 signal() 函数时会将之前注册的信号处理函数如果有的话替换为新的处理函数并返回之前注册的处理函数。 下面是一个简单的示例演示如何使用 signal() 函数来捕获 SIGINT 信号并设置相应的处理函数 #include stdio.h
#include signal.h
#include unistd.hvoid sigint_handler(int signum) {printf(Caught SIGINT signal, exiting...\n);exit(1);
}int main() {// 注册 SIGINT 信号处理函数signal(SIGINT, sigint_handler);printf(Press CtrlC to send a SIGINT signal...\n);while (1) {// 进程持续执行}return 0;
} 在示例中我们定义了一个名为 sigint_handler 的函数用于处理接收到的 SIGINT 信号。然后在 main() 函数中使用 signal() 函数注册了这个信号处理函数。当用户按下 CtrlC 发送 SIGINT 信号时该处理函数将被调用。 需要注意的是signal() 函数在一些情况下可能会有一些不确定的行为因此推荐使用更加可靠和灵活的 sigaction() 函数来注册信号处理函数。 信号种类 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN1 36) SIGRTMIN2 37) SIGRTMIN3
38) SIGRTMIN4 39) SIGRTMIN5 40) SIGRTMIN6 41) SIGRTMIN7 42) SIGRTMIN8
43) SIGRTMIN9 44) SIGRTMIN10 45) SIGRTMIN11 46) SIGRTMIN12 47) SIGRTMIN13
48) SIGRTMIN14 49) SIGRTMIN15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX 信号既有名字又有值说明是用宏定义的 没有0号信号用来标识进程正常退出 信号一共62个信号是从0-31和34-64 0-31是普通信号 * SIGHUP (1)挂起信号通常用于重启进程。
* SIGINT (2)中断信号通常由CtrlC发出用于停止进程。
* SIGQUIT (3)退出信号通常由Ctrl\发出用于强制终止进程。
* SIGILL (4)非法指令信号通常由进程执行无效的机器指令而引起。
* SIGTRAP (5)陷阱信号通常用于调试。
* SIGABRT (6)异常终止信号通常由abort()函数发出表示进程存在严重问题需要终止。
* SIGBUS (7)总线错误信号通常由非法内存访问引起。
* SIGFPE (8)浮点异常信号通常由除零或其他数学错误引起。
* SIGKILL (9)强制终止信号无法被捕获、忽略或阻塞用于强制杀死进程。
* SIGUSR1 (10)用户定义信号1。
* SIGSEGV (11)段错误信号通常由非法内存访问引起。
* SIGUSR2 (12)用户定义信号2。
* SIGPIPE (13)管道破裂信号通常发生在进程向已关闭的管道写入数据时。
* SIGALRM (14)定时器信号通常由alarm()函数或setitimer()函数发出。
* SIGTERM (15)终止信号通常用于请求进程正常停止。
* SIGSTKFLT (16)堆栈错误信号通常发生在堆栈溢出时。
* SIGCHLD (17)子进程状态改变信号通常用于父进程监控子进程的状态。
* SIGCONT (18)继续执行信号通常用于恢复被停止的进程。
* SIGSTOP (19)停止信号无法被捕获、忽略或阻塞用于暂停进程。
* SIGTSTP (20)挂起信号通常由CtrlZ发出用于暂停进程。
* SIGTTIN (21)后台读取信号通常发生在后台进程尝试从终端读取数据时。
* SIGTTOU (22)后台写入信号通常发生在后台进程尝试向终端写入数据时。
* SIGURG (23)紧急数据可读信号通常发生在带外数据到达时。
* SIGXCPU (24)CPU时间限制信号通常发生在进程超过CPU时间限制时。
* SIGXFSZ (25)文件大小限制信号通常发生在进程超过文件大小限制时。
* SIGVTALRM (26)虚拟定时器信号通常由setitimer()函数发出。
* SIGPROF (27)CPU时间分配信号通常由setitimer()函数发出。
* SIGWINCH (28)窗口大小改变信号通常发生在终端窗口大小改变时。
* SIGIO (29)异步I/O信号通常用于异步I/O操作。
* SIGPWR (30)电源故障信号通常发生在电源故障时。
* SIGSYS (31)系统调用错误信号通常由进程执行非法的系统调用而引起。 每一个进程都有一张自己的函数指针数组表数组的下标就和信号编号相关的 对于普通信号来讲进程收到信号之后进程要表示自己是否收到了某种信号 怎么表示是否收到呢 可以使用位图的方式0000 0000
比特位的位置决定信号编号
比特位的内容决定是否收到信号
在进程控制块中,有一个字段就是位图
task_struct
{//信号位图uint32_t sigmap;
} OS向目标进程发送信号其实就是向目标进程pcb的位图写信号 注意无论信号有多少种产生方式永远只能让OS向目标进程发送OS是进程的管理者 每个进程与信号相关都两个字段 1.函数指针数组 2.信号位图 34-64是实时信号 ctrlz:默认暂停进程 ctrl\默认是终止进程 signal系统调用可以自定义信号的处理方法 man 7 signal可以查看信号的默认处理方法 注意像9号等信号不能自定义信号的处理方法 通过系统调用实现信号产生 Kill系统调用 kill 系统调用的原型如下 #include sys/types.h
#include signal.h
int kill(pid_t pid, int sig);
其中pid 参数指定要发送信号的目标进程的进程IDsig 参数指定要发送的信号编号。 以下是 kill 系统调用的常见用法 终止进程使用 SIGKILL 信号编号为9可以强制终止指定进程。 kill(pid, SIGKILL); 请注意kill 系统调用只能发送信号给具有合法权限的目标进程。此外kill 系统调用返回0表示成功返回-1表示出错并设置相应的错误码。 raise raise 是一个函数用于向当前进程发送信号。它的原型如下 #include signal.h
int raise(int sig);
其中sig 参数指定要发送的信号编号。使用 raise 函数可以向当前进程发送指定的信号。例如以下代码将向当前进程发送 SIGTERM 信号请求进程优雅地终止
raise(SIGTERM);
与 kill 系统调用不同raise 函数只能向当前进程发送信号不能向其他进程发送信号。此外raise 函数返回0表示成功返回非零值表示出错通常是因为指定了无效的信号编号。 abort abort 是一个函数用于向当前进程发送 SIGABRT 信号并终止进程。它的原型如下
#include stdlib.h
void abort(void);
abort 函数会向当前进程发送 SIGABRT 信号该信号的默认处理方式是生成一个核心转储文件并终止进程。abort 函数通常被用于在程序发生无法恢复的错误时终止程序并生成一个核心转储文件以供调试分析。例如在以下代码中如果 malloc 函数返回空指针我们可以使用 abort 函数终止程序并生成一个核心转储文件
#include stdlib.h
void *ptr malloc(size);
if (ptr NULL) {fprintf(stderr, Error: failed to allocate memory.\n);abort();
}
请注意与 exit 函数不同abort 函数不会调用已注册的退出处理程序也不会关闭流或执行任何其他清理操作。因此abort 函数应该谨慎使用仅在必要时才使用。 异常发送信号 int a10;
a/0;如果异常不做处理杀掉该进程os会一直调度该进程然后又出异常循环往复。 寄存器寄存器里内容进程上下文 进程中的程序异常进程一定会退出吗默认情况下会退出如果用signal自定义信号处理方法的话就不一定了 如果进程出异常和我们的编译器还有关系吗进程会被OS直接终止了 一般出异常是没有办法去处理这个异常一般出异常我们会显示这个异常让我们自己看到 软件条件产生异常 alarm #include unistd.h
unsigned int alarm(unsigned int seconds);
调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动
作是终止当前进程,如果 seconds 参数为0则之前设置的闹钟将被取消并返回剩余的闹钟时间。int main()
{alarm(1);int cnt0;while(true){coutalarm: cntendl;}return 0;
} 操作系统中的时间 1.所有用户的行为都是以进程的形式在OS中表现的 2.OS只要把进程调度好就能完成所有的用户任务 3.CMOS周期性高频率的向CPU发送时钟中断 OS本质就是一个死循环操作系统的执行是基于硬件中断的 如果大家还有不懂或者建议都可以发在评论区我们共同探讨共同学习共同进步。谢谢大家