校园服装网站建设预算,怎么增加网站的权重,中国建筑第八工程局有限公司,施工企业甲乙资质原创首发于CSDN#xff0c;转载请注明出处#xff0c;谢谢! https://blog.csdn.net/weixin_46959681/article/details/114527183 文章目录 什么是信号信号的处理#xff5c;信号处理函数初级版 signal#xff5c;信号处理函数高级版 sigaction sigqueue 信号量参考资… 原创首发于CSDN转载请注明出处谢谢! https://blog.csdn.net/weixin_46959681/article/details/114527183 文章目录 什么是信号信号的处理信号处理函数初级版 signal信号处理函数高级版 sigaction sigqueue 信号量参考资料文章更新记录 什么是信号
实际上信号在操作系统中为 软中断 基本上所有的程序都需要处理信号。信号为计算机系统提供了一种处理异步事件的方法。例如因程序编译运行错误导致终端打印大量乱码此时仅需输入Ctrl C 计算机系统自身的信号机制会强制停止正在运行的错乱程序。
信号的处理
信号的处理有三种方法 捕捉信号。告诉内核用户希望如何处理某一种信号。编写一个信号处理函数将该函数传给内核。当信号产生时由内核来调用用户自定义的函数实现某种信号的处理。另外通过自定义编程的信号处理函数可以“修改”系统的默认动作如 Crtl C具体编程实例请看下文忽略信号。大多数信号可使用该方式处理但有两种信号不能被忽略SIGKILL、SIGSTOP。因其向内核和超级用户提供了进程终止和停止的可靠方法若忽略则某个进程就变成了没人能管理的的进程系统的默认动作。所有被设计好的函数在系统中都有默认的处理动作当产生该信号系统会自动执行。实际工作中绝大部份的处理方式都直接了当就是直接杀死该进程 “kill -9 pid” 。 信号处理函数初级版 signal
函数原型
#include signal.h
//实际的信号处理函数。
typedef void (*sighandler_t)(int);
//信号注册函数。signum为信号的编号handler为中断函数的指针。
sighandler_t signal(int signum, sighandler_t handler);通过信号处理的初级函数 signal 以指令 Ctrl C 为例实现 信 号 捕 捉 信号捕捉 信号捕捉 与 默 认 动 作 修 改 默认动作修改 默认动作修改。
演示代码signal1.c
/* signal1.c */
#include stdio.h
#include stdlib.h
#include signal.hvoid handler(int signum)
{printf(Get signum %d.\n,signum);switch(signum){case 2:printf(SIGINT\n);break;case 10:printf(SIGUSR1\n);}printf(Never quit.\n);
}int main(){signal(SIGINT,handler);signal(SIGUSR1,handler);while(1);return 0;
}运行以上代码当输入 Ctrl C 时终端显示 signum 2 能看到系统默认的强制退出动作经过以上编写的自定义信号函数后“无效”了唯有通过指令 k i l l kill kill 杀死该进程。
输入 Ctrl C 强制退出时使用 kill 命令处理
信号处理函数高级版 sigaction sigqueue s i g n a l signal signal 是初级的信号处理函数仅能发出处理的“动作”。若是要进一步携带其他消息如 信号值、字符串、PID号、时钟、内存地址 等等内容则需要更高级的信号处理函数 s i g a c t i o n sigaction sigaction 、 s i g q u e u e sigqueue sigqueue。
对于这两个高级信号处理函数的构造、具体参数等等细节笔者还在摸索阶段请读者自行使用 man 手册以及阅读参考资料里的博文 —— Linux 信号signal。笔者这里直接贴出教学视频里的两段代码感兴趣的读者请细细品味。
第一步运行接收端代码文件 sigaction.c 生成的编译文件 receive 。
/* sigaction.c */
#include stdio.h
#include stdlib.h
#include signal.h
#include sys/types.h
#include unistd.h
//发送端所发的一切信息都可用指针info读取。
void handler(int signum, siginfo_t *info,void *context)
{printf(Get signum %d\n,signum);//接收信号并判断内容是否为空。if(context ! NULL){printf(Get data %d\n,info-si_int);//printf(Get data %d\n,info-si_value.sival_int);printf(From Sends pid %d\n,info-si_pid);}
}int main()
{struct sigaction act;printf(Receives pid %d\n,getpid());act.sa_sigaction handler;//宏表示能接收数据。act.sa_flags SA_SIGINFO;//int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);sigaction(SIGUSR1,act,NULL); while(1);return 0;
}第二步运行发送端代码文件 sigqueue.c 生成的编译文件 send 。
/* sigqueue.c */
#include stdio.h
#include stdlib.h
#include string.h
#include signal.h
#include sys/types.h
#include unistd.hint main(int argc, char **argv)
{int signum;int pid;signum atoi(argv[1]);pid atoi(argv[2]);union sigval value;value.sival_int 10000;//int sigqueue(pid_t pid, int sig, const union sigval value);sigqueue(pid,signum,value);printf(Sends pid %d\n,getpid());printf(Over.\n);return 0;
}运行结果
发送端接收端
信号量
信号量(semaphore) 与笔者在前两篇博文中介绍的通信机制 —— 管道 、消息队列与共享内存 —— 不同 本质上可视为一个 计数器 。信号量具备初始值若 初始值 0说明其处于“空闲状态”若 初始值 0说明其处于“占用状态”。当其处于“占用状态”时不论是进城或线程都要处于等待状态等待被“唤醒”PV操作。
信号量用于实现系统进程间的互斥与同步以及同一进程的不同线程的同步而不是用来存储进程间的通信数据。 拓展 同步处理 Linux 系统里进程的竞争就是同步安排进程执行的先后顺序就是同步每个进程都有一定的个先后执行顺序互斥访问不可共享的临界资源如物理设备会引发两个新的控制问题互斥可以被说成特殊的同步吗竞争当父子进程又或者并发进程竞争使用同一个资源的时候我们就称为竞争进程。 函数原型
//创建一个信号量组成功返回信号量集ID失败返回-1。
int semget(key_t key,int nsems,int semflg);
//对信号量组进行操作改变信号量的值PV操作。
int semop(int semid, struct sembuf *sops, size_t nsops);
//控制信号量的相关信息。
int semctl(int semid, int semnum, int cmd, ...);上文中的 P V PV PV 操作笔者在这里给出一小段含 fork() 函数的演示代码对于代码中更加细节的部分如 sembuf 等已经有大量的博客给出了相应的解释和实例代码请看最下行的参考博文这里不再多费笔墨。
演示代码semaphore.c
/* semaphore.c */
#include stdio.h
#include error.h
#include sys/types.h
#include sys/ipc.h
#include sys/sem.h
#include unistd.h
union semun
{int val; /* Value for SETVAL */struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short *array; /* Array for GETALL, SETALL */struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */
};void sem_p(int sem_id)
{struct sembuf set;set.sem_num 0;set.sem_op -1;set.sem_flg SEM_UNDO;semop(sem_id,set,1);printf(sem_p OK.\n);
}void sem_v(int sem_id)
{struct sembuf set;set.sem_num 0;set.sem_op 1;set.sem_flg SEM_UNDO;semop(sem_id,set,1);printf(sem_v OK.\n);
}int main(int argc, char **argv[])
{int sem_id;pid_t pid;key_t key;key ftok(.,o);printf(key %x\n,key);//创建信号量。sem_id semget(key,1,IPC_CREAT|0666);//设置联合体内信号量的值初始化信号量组以及信号量值为零。union semun initsem;initsem.val 0;semctl(sem_id,0,SETVAL,initsem);pid fork();if(pid 0){//父进程。sem_p(sem_id);printf(Process father: pid %d.\n,getpid());sem_v(sem_id);semctl(sem_id,0,IPC_RMID);//删除信号量集。printf(sem_del OK.\n);}else if(pid 0){//子进程。printf(Process child: pid %d.\n,getpid());sem_v(sem_id);}else{printf(Fork fail.\n);}return 0;
}运行结果
主函数内调用函数 f o r k ( ) fork() fork() 产生父子进程当父进程运行时因演示代码中联合体内的信号量初始值为零 i n i t s e m . v a l 0 initsem.val 0 initsem.val0 无法执行 P 操作 sem_p 进入等待状态系统进程跳转先执行子进程。子进程执行完毕后经过完整的 P V PV PV 操作父进程得以继续执行完毕。 笔者没有学习过计算机操作系统上述一段只能从代码层面自圆其说显得过于粗浅。 参考资料
参考博客 进程间通信的五种方式参考博客 进程间的五种通信方式介绍-详解知乎文章 进程间通信的方式四信号量 文章更新记录
文章框架完成。「2021.3.8 12:05」“信号的处理”一节完成。 「2022.3.15 11:21」“信号处理函数高级版 sigaction sigqueue”一节完成。「2022.3.17 22:50」“信号量”一节完成。「2021.3.19 17:24」 P.S. 《计算机操作系统》与《计算机组成原理》是每一个嵌入式开发者必备的计算机内功心法。