深圳做网站有哪些,网站上面的水印怎么做的,福州企业网站开发,wordpress 置顶字段文章目录 进程间通讯 - 信号信号完整的信号周期信号的编号信号的产生发送信号1 kill 函数(他杀)作用#xff1a;语法#xff1a;示例#xff1a; 2 raise函数(自杀)作用#xff1a;示例#xff1a; 3 abort函数(自杀)作用#xff1a;语法#xff1a;示例#xff1a; 4 … 文章目录 进程间通讯 - 信号信号完整的信号周期信号的编号信号的产生发送信号1 kill 函数(他杀)作用语法示例 2 raise函数(自杀)作用示例 3 abort函数(自杀)作用语法示例 4 alarm函数(自杀)只能延迟执行作用语法示例 5 settimer函数(定时器)[扩展]延迟重复执行 6 pause函数 自定义信号处理1 signal作用语法 2 sigaction作用:语法struct sigaction结构体 可重入函数概述注意 信号集概述 自定义信号集函数信号阻塞集概述sigprocmask函数作用:语法 进程间通讯 - 信号 中文名:进程间通讯 英文名:IPC 英文全称:Inter Processes Communication 作用进程间互相传递信息 数据传输一个进程需要将它的数据发送给另一个进程。
资源共享多个进程之柯共享同样的资源。
通知事件一个进程需要向另一个或一组进程发送消息通知它们发生了某种事件。
进程控制有些进程希望完全控制另一个进程的执行如Debug进程此时控制进程希望能够拦截另一个进程的所有操作并能够及时知道它的状态改变。分类 信号管道文件共享网络【socket】 发展史 最初的UNIX进程间通信SYSTEMV 进程间通信POSIX 进程间通信PosIX:PortableOperatingSysteminterface 可移植操作系统接口Socket进程间通信Linux把优势都继承了下来并形成了自己的IPC Linux进程间通信 信号 信号是 Linux 进程间通信的最古老的方式 特点 简单不能携带大量信息满足某个特设条件才发出。【也就是不管发 管收】 注意 1 信号是一种异步通信方式2 信号是软件中断它是在软件层次上对中断机制的一种模拟。3 信号可以导致一个正在运行的进程被另一个正在运行的异步进程中断转而处理某一个突发事件。4 进程不必等待信号的到达进程也不知道信号什么时候到达。5 信号可以直接进行用户空间进程和内核空间进程的交互内核进程可以利用它来通知用户空间进程发生哪些系统事件 名词解释 同步事件、操作或进程是有序的一个操作必须在另一个操作完成后开始执行异步事件、操作或进程是独立的可以在不等待其他操作完成的情况下开始执行中断机制是现代计算机系统中的基本机制之一完成了对计算机各个事件如时钟、键盘等响应工作硬件中断是由硬件设备触发的中断如时钟中断、串口接收中断、外部中断等。 完整的信号周期 发送信号接收信号信号的处理默认、忽略、自定义信息的注销 信号的编号
注意:信号不能自定义每个信号的名字都以字符 SIG 开头。
每个信号和一个数字编码相对应在头文件 signum.h 中这些信号都被定义为正整数。信号名定义路径/usr/include/asm-generic/signal.h在Linux下要想查看这些信号和编码的对应关系可使用命令kill -l不存在编号为0的信号。1-31号信号称之为常规信号(也叫普通信号,标准信号)34-64号信号称之为实时信号(自定义信号)通过man 7 signal查看信号帮助文档注意:9) SIGKILL 和 19) SIGSTOP 信号不允许忽略和捕捉只能执行默认动作。重要SIGQUIT信号由:Ctrl \触发SIGINT信号由:ctrlc触发注意信号不能自定义 kill -lman 7 signal 通过 kill -l 查看每个信号的名字都以字符 SIG 开头。每个信号和一个数字编码相对应在头文件ignal.h中这些信号都被定义为正整数。信号名定义路径/usr/include/asm-generic/signal.h 不存在编号为0的信号。1-31号信号称之为常规信号也叫普通信号标准信号34-64号信号称之为实时信号自定义信号
通过man 7 signal 查看信号帮助文档
注意9SIGKILL和19SIGSTOP信号不允许忽略和捕捉只能执行默认动作。重要
SIGQUIT 信号由Ctr\触发
SIGINT 信号由ctrl c触发信号的产生 1, 当用户按某些终端键时将产生信号。 终端上按“Ctrlc”组合键通常产生中断信号 SIGINT 终端上按“Ctrl\”键通常产生中断信号 SIGQUIT 终端上按“Ctrlz”键通常产生中断信号 SIGSTOP 等。2,硬件异常将产生信号。 除数为0无效的内存访问等。这些情况通常由硬件检测到并通知内核然后内核产生适当的信号发送给相应的进程。3,软件异常将产生信号。 当检测到某种软件条件已发生(如定时器 alarm)并将其通知有关进程时产生信号。4,调用系统函数(如kill、raise、abort)将发送信号。
注意接收信号进程和发送信号进程的所有者必须相同或发送信号进程的所有者必须是超级用户。5,运行 kill/killall 命令将发送信号。 此程序实际上是使用 kill 函数来发送信号。也常用此命令终止一个失控的后台进程。发送信号
1 kill 函数(他杀)
作用
给指定进程发送指定信号(不一定杀死)他杀
语法 头文件#include sys/types.h#include signal.h
函数int kill(pid_t pid, int sig);
参数pid取值有4种情况pid〉O将信号传送给进程 ID 为 pid 的进程。pid0将信号传送给当前进程所在的进程组中的所有进程。pid-1将信号传送给系统内所有的进程。pid〈-1将信号传给指定进程组的所有进程。这个进程组号等于pid的绝对值。 sig信号的编号这里可以填数字编号也可以填信号的宏定义可以通过命令ki11]”为字母)进行相应查看。不推荐直接使用数字应使用宏名因为不同操作系统信号编号可能不同但名称一致。 返回值成功0失败-1示例
#include stdio.h
#include signal.h
#include sys/types.h
#include wait.h
#include unistd.h
int main(int argc, char const *argv[])
{int pid fork();if (pid 0){printf(子进程开始\n);while (1);printf(子进程end\n);}else if (pid 0){printf(当前进程开始\n);printf(3秒后发送信号给子进程\n);sleep(3);// 给子进程发送 SIGINT 信号kill(pid, SIGINT);printf(当前进程已经发送了信号\n);int id wait(NULL);printf(进程%d被回收了\n,id);}return 0;
}2 raise函数(自杀)
#include signal.h
作用
自己给自己发信号
语法
函数int raise(int sig);
参数:sig信号编号
返回值成功0失败非 0
注意:该函数等价与kill(getpid(),sig);示例
#include stdio.h
#include signal.h
#include sys/types.h
#include wait.h
#include unistd.h
int main(int argc, char const *argv[])
{printf(当前进程开始 \n);//发送停止信号raise(SIGSTOP);while (1)printf(当前进程结束 \n);return 0;
}3 abort函数(自杀)
作用
给自己发送异常终止信号 6) SIGABRT并产生 core 文件等价于 kill(getpid(), SIGABRT)
core文件(了解)
core就是内核
core文件会包含了程序运行时的内存寄存器状态堆栈指针内存管理信息还有各种
函数调用堆栈信息等我们可以理解为是程序工作当前状态存储生成第一个文件许多
的程序出错的时候都会产生一个core文件通过工具分析这个文件我们可以定位到程
序异常退出的时候对应的堆栈调用等信息找出问题所在并进行及时解决。语法
所需头#include stdlib.h
函数void abort(void);
注意:1,使用abort函数结束进程,进程结束前会刷新缓冲区并关闭所有的文件描述符0/1/22,即使 SIGABRT 信号被加入阻塞集一旦进程调用了 abort 函数进程也还是会被终止示例
#include stdio.h
#include stdlib.h
// abort() 给自己发送异常终止信号
int main(int argc, char const *argv[])
{printf(当前进程开始 \n);abort();while (1)printf(当前进程结束 \n);return 0;
}
4 alarm函数(自杀)
只能延迟执行
#include unistd.h
作用 设置定时器(闹钟)。在指定时间后(单位秒)内核会给当前进程发送 14SIGALRM 信号。进程收到该信号默认动作终止。每个进程都有且只有唯一的一个定时器。取消定时器 alarm(0)返回旧闹钟余下秒数。语法
函数unsigned int alarm(unsigned int seconds);
参数:seconds:时间,单位秒
返回值:若以前没有设置过定时器或设置的定时器已超时返回0否则返回定时器剩余的秒数并重新设定定时器注意
定时与进程状态无关(即自然定时法)就绪、运行、挂起(阻塞、暂停)、终止、僵尸……无论进程处于何种状态alarm 都计时不阻塞当前进程示例
#include stdio.h
#include unistd.h
// alarm函数(自杀)
int main(int argc, char const *argv[])
{printf(当前进程开始 \n);alarm(5); //每过五秒就自杀 不阻塞进程 也就不妨碍下面进程的执行int i 0;while (1){sleep(1);i;printf(已经过去了%d秒\n, i);}printf(当前进程结束 \n);return 0;
} 示例2 设置了 0 就是取消定时
因为死循环 就会一直执行 不会发出杀死进程的信号
#include stdio.h
#include unistd.h
// alarm函数(自杀)
int main(int argc, char const *argv[])
{printf(当前进程开始 \n);alarm(5); //每过五秒就自杀 不阻塞进程 也就不妨碍下面进程的执行alarm(0); // 0 代表取消int i 0;while (1){sleep(1);i;printf(已经过去了%d秒\n, i);}printf(当前进程结束 \n);return 0;
} 5 settimer函数(定时器)[扩展]
延迟重复执行
等价 killsleep 【开发实际 会选用 kill sleep】
settimer 开发有延迟重复执行就用
alarm 开发需要延迟执行就用它
但是 kill sleep 其实就够用 作用 设置定时器(闹钟)。 可代替 alarm 函数。精度微秒 us可以实现周期定时。 语法 所需头文件#include sys/time.h函数
int setitimer(int which, const struct itimerval *new_value, structitimerval *old_value);参数:which指定定时器类型可以是以下三个值之一a) 自然定时ITIMER_REAL → 14SIGALRM 计算自然时间b) 虚拟空间计时(用户空间)ITIMER_VIRTUAL → 26SIGVTALRM 只计算进程占用 cpu 的时间c) 运行时计时(用户内核)ITIMER_PROF → 27SIGPROF 计算占用 cpu及执行系统调用的时间new_value一个指向struct itimerval结构体的指针用于指定新的定时器值启动时间和间隔时间。old_value一个指向struct itimerval结构体的指针用于获取旧的定时器值即之前设置的定时器值。如果不需要获取旧的定时器值则可以传入NULL。注意:设置的value一定要全部设置值,因为结构体成员变量默认值为随机数struct itimerval 结构体 struct itimerval
{struct timerval it_interval; // 间隔时间struct timerval it_value; // 延迟时间
};struct timerval结果体 struct timeval
{long tv_sec; // 秒long tv_usec; // 微秒
};示例 #include stdio.h
#include signal.h
#include sys/time.h
extern void fun01();
int main(int argc, char const *argv[])
{
//注意 因为 是结构体 所以成员变量初始值 是随机数 使用时 全部初始化 signal(SIGALRM,fun01);struct itimerval val;val.it_value.tv_sec3; // 设置 延迟时间为3sval.it_value.tv_usec0;val.it_interval.tv_sec1.5; // 设置 间隔时间为1sval.it_interval.tv_usec0;setitimer(ITIMER_REAL,val,NULL);while(1);return 0;
}
void fun01()
{printf(收到信号\n);// _exit(0);
}6 pause函数
作用捕捉信号会阻塞当前进程
语法 #include unistd.h int pause(void);
返回值直到捕获到信号pause返回 -1 并且errno 被设置为 EINTR示例
#include stdio.h
#include unistd.h
// pause()函数 会阻塞进程
int main(int argc, char const *argv[])
{printf(开始咯\n);pause();printf(开始咯\n);return 0;
}自定义信号处理
信号处理 默认 SIG_DEF忽略 SIG_IGN自定义 函数名 注意 SIGSTOP 与 SIGKILL 这两个信号 不能或略 不能自定义 只能默认 1 signal
作用
可以用于进程间通讯
语法
# include signal.h
函数:sighandler_t signal(int signum, sighandler_t handler);
参数:signum信号的编号这里可以填数字编号也可以填信号的宏定义可以通过
命令 kill - l(l 为字母)进行相应查看。handler : 取值有 3 种情况SIG_IGN忽略该信号SIG_DFL执行系统默认动作信号处理函数名自定义信号处理函数//定义的一个函数指针typedef void(*sighandler_t)(int);
返回值:成功第一次返回 NULL下一次返回此信号上一次注册的信号处理函数的地址。如果需要使用此返回值必须在前面先声明此函数指针的类型。
失败返回 SIG_ERR通过 kill -l 查看 每个信号的名字都以字符 SIG 开头。每个信号和一个数字编码相对应在头文件ignal.h中这些信号都被定义为正整数。信号名定义路径/usr/include/asm-generic/signal.h 不存在编号为0的信号。 1-31号信号称之为常规信号也叫普通信号标准信号34-64号信号称之为实时信号自定义信号 示例1
注意 sigCode 返回的是 信号编号
#include stdio.h
#include signal.h
void fun(int sigCode)
{printf(sigCode %d\n, sigCode);printf(sigCode 是用来获取信号编号的);printf(你好,这是只有按下 CTRLc 后显示的函数内容\n);
}
int main(int argc, char const *argv[])
{// SIGINT 键盘ctrlc 就触发信号// signal(SIGINT, SIG_DFL); // 这是默认处理 也就是停止进程// signal(SIGINT,SIG_IGN); //SIG_IGN 忽略// 绑定信号// 当按下 CTRL c 就去执行函数 funsignal(SIGINT, fun);while (1);return 0;
}示例2
#include stdio.h
#include sys/types.h
#include unistd.h
#include wait.h
#include signal.h
int tag 1;
void fun()
{tag 0;
}
void fun02()
{printf(子进程结束了\n);
}
int main(int argc, char const *argv[])
{int pid fork();if (pid 0){signal(SIGUSR1, fun);for (int i 0; i 100 tag; i){sleep(1);printf(已下载:%d%%\n, i 1);}printf(结束下载\n);kill(getpgrp(), SIGUSR2);}else if (pid 0){signal(SIGUSR2, fun02);printf(5秒后停止下载\n);sleep(5);kill(pid, SIGUSR1);wait(NULL);}return 0;
}2 sigaction
作用:
检查或修改指定信号的设置或同时执行这两种操作。
语法
#include signal.h 函数:int sigaction(int signum, const struct sigaction *act, struct sigaction* oldact);参数:signum要操作的信号。act 要设置的对信号的新处理方式传入参数。oldact原来对信号的处理方式传出参数。注意:如果act指针非空,则要改变指定信号的处理方式(设置),如果oldact指针非空,则系统将此前指定信号的处理方式存入oldact。返回值:成功0失败-1struct sigaction结构体
struct sigaction
{void (*sa_handler)(int); // 旧的信号处理函数指针 void (*sa_sigaction)(int, siginfo_t *, void *); // 新的信号处理函数指针sigset_t sa_mask; // 信号阻塞集int sa_flags; // 信号处理的方式void (*sa_restorer)(void); // 已弃用
};
/*1,sa_handler,sa_sigaction:信号处理函数指针,和signal()里的函数指针用法一样应根据情况给 sa_sigaction、sa_handler 两者之一赋值其取值如下a SIGIGN忽略该信号b SIGDFL执行系统默认动作c 处理函数名自定义信号处理函数2,sa_mask信号阻塞集在信号处理函数执行过程中临时屏蔽指定的信号。3,sa_flags用于指定信号处理的行为通常设置为 0表使用默认属性。它可以是以下值的“按位或”组合SA_RESTART使被信号打断的系统调用自动重新发起已经废弃SA_NOCLDSTOP使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD信号。SA_NOCLDWAIT使父进程在它的子进程退出时不会收到 SIGCHLD 信号这时子进程如果退出也不会成为僵尸进程。SA_NODEFER使对信号的屏蔽无效即在信号处理函数执行期间仍能发出这个信号。SA_RESETHAND信号处理之后重新设置为默认的处理方式SA_SIGINFO使用 sa_sigaction 成员而不是 sa_handler 作为信号处理
函数void(*sa_sigaction)(int signum, siginfo_t *info, void *context);
参数说明signum:信号的编号。info:记录信号发送进程信息的结构体。context:可以赋给指向ucontext_t类型的一个对象的指针,以引用在传递信号时被中断的接收进程或线程的上下文。
*/#include stdio.h
#include signal.h
void fun()
{printf(已处理\n);
}
int main(int argc, char const *argv[])
{struct sigaction mys;mys.sa_handler fun;sigaction(SIGINT, mys, NULL);while (1);return 0;
}可重入函数
概述
一种特殊的函数
多个进程执行同一个函数,多个进程之间互不干扰,该函数为可重入函数注意
1、不使用或返回 静态的数据、全局变量除非用信号量互斥。
2、不调用动态内存分配、释放的函数。
3、不调用任何不可重入的函数如标准 I/O 函数系统提供的可重入函数 信号集
概述 在PCB中有两个非常重要的信号集。一个称之为“阻塞信号集”另一个称之为“未决信号集”。 这两个信号集都是内核使用位图机制来实现的。但操作系统不允许我们直接对其进行位操作。而需自定义另外一个集合借助信号集操作函数来对 PCB 中的这两个信号集进行修改 信号阻塞集将某些信号加入 集合对他们设置屏蔽当屏蔽 x 信号后再收到该信号该信号的处理将暂缓。 未决信号集未被处理的信号集合。自定义信号集函数
所需头文件 #include signal.h
函数int sigemptyset(sigset_t *set); //将 set 集合置空int sigfillset(sigset_t *set) //将所有信号加入 set 集合int sigaddset(sigset_t *set, int signo); //将 signo 信号加入到 set合int sigdelset(sigset_t *set, int signo); //从 set 集合中移除 signo信号int sigismember(const sigset_t *set, int signo); //判断信号是否存在于集合中信号阻塞集
概述 信号阻塞集也称信号屏蔽集、信号掩码。每个进程都有一个阻塞集创建子进程时子进程将继承父进程的阻塞集。信号阻塞集用来描述哪些信号递送到该进程的时候被阻塞在信号发生时记住它,直到进程准备好时再将信号通知进程。 所谓阻塞并不是禁止传送信号, 而是暂缓信号的传送。若将被阻塞的信号从信号阻塞集中删除,且对应的信号在被阻塞时发生了进程将会收到相应的信号。 我们可以通过 sigprocmask() 修改当前的信号阻塞集来改变信号的阻塞情况。sigprocmask函数
作用:
检查或修改信号阻塞集根据 how 指定的方法对进程的阻塞集合进行修改新的信号阻塞集由 set 指定而原先的信号阻
塞集合由 oldset 保存。
语法
所需头文件
#include signal.h
函数int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
参数how:信号阻塞集合的修改方法,有3种情况:SIG_BLOCK:添加向信号阻塞集合中添加set信号集,新的信号掩码是set和旧信号掩码的并集.相当于maskmask|set。SIG_UNBLOCK:删除从信号阻塞集合中删除set信号集,从当前信号掩码中去除set中的信号.相当于maskmask~set。SIG_SETMASK:替换 将信号阻塞集合设为set信号集,相当于原来信号阻塞集的内容清空,然后按照set中的信号重新设置信号阻塞集。相当于maskset。set:要操作的信号集地址。若set为NULL,则不改变信号阻塞集合,函数只把当前信号阻塞集合保存到oldset中oldset:保存原先信号阻塞集地址#include stdio.h
#include signal.h
#include sys/types.h
#include unistd.h
// 进程的加锁 与解锁
void fun()
{printf(已处理\n);
}
int main(int argc, char const *argv[])
{signal(SIGINT, fun);sigset_t set;sigemptyset(set);sigaddset(set, SIGINT);sigprocmask(SIG_BLOCK, set, NULL); //设置阻塞printf(3秒后移除对SIGINT的阻塞\n);sleep(3);sigprocmask(SIG_UNBLOCK, set, NULL); //解除阻塞while (1);return 0;
}SIG_BLOCK:添加向信号阻塞集合中添加set信号集,新的信号掩码是set和旧信号掩码的并集.相当于maskmask|set。SIG_UNBLOCK:删除从信号阻塞集合中删除set信号集,从当前信号掩码中去除set中的信号.相当于maskmask~set。SIG_SETMASK:替换 将信号阻塞集合设为set信号集,相当于原来信号阻塞集的内容清空,然后按照set中的信号重新设置信号阻塞集。相当于maskset。
set:要操作的信号集地址。若set为NULL,则不改变信号阻塞集合,函数只把当前信号阻塞集合保存到oldset中
oldset:保存原先信号阻塞集地址#include stdio.h
#include signal.h
#include sys/types.h
#include unistd.h
// 进程的加锁 与解锁
void fun()
{printf(已处理\n);
}
int main(int argc, char const *argv[])
{signal(SIGINT, fun);sigset_t set;sigemptyset(set);sigaddset(set, SIGINT);sigprocmask(SIG_BLOCK, set, NULL); //设置阻塞printf(3秒后移除对SIGINT的阻塞\n);sleep(3);sigprocmask(SIG_UNBLOCK, set, NULL); //解除阻塞while (1);return 0;
}