https://www.php.cn/php-ercikaifa-345122.html
https://m.php.cn/article/421935.html
一、在Linux操作系统中有哪些信号
1、简单介绍信号

信号是事件发生时对进程的通知机制,有时又称为软件中断。一个进程可以向另一个进程发送信号,比如子进程结束时都会向父进程发送一个SIGCHLD(17号信号)来通知父进程,所以有时信号也被当作一种进程间通信的机制。
在linux系统下,通常我们使用 kill -9 XXPID来结束一个进程,其实这个命令的实质就是向某进程发送SIGKILL(9号信号),对于在前台进程我们通常用Ctrl+c快捷键来结束运行,该快捷键的实质是向当前进程发送SIGINT(2号信号),而进程收到该信号的默认行为是结束运行

2、常用信号
下边这些信号,可以使用kill -l命令进行查看

下边介绍几个比较重要且常用的信号:

二、PHP中处理信号相关函数
PHP的pcntl扩展以及posix扩展为我们提供了若干操作信号的方法(若想使用这些函数,需要先安装这几个扩展)
下边具体介绍几个我在本次任务中用到的方法:
declare
declare结构用来设定一段代码的执行指令。declare的语法和其它流程控制结构相似

declare (directive)
statement

directive部分允许设定declare代码段的行为。目前只认识两个指令:ticksencoding。declare代码段中的 statement部分将被执行——怎样执行以及执行中有什么副作用出现取决于directive中设定的指令
Ticks
Tick(时钟周期)是一个在declare代码段中解释器每执行N条可计时的低级语句就会发生的事件N的值是在declare 中的directive部分用ticks=N来指定的。不是所有语句都可计时。通常条件表达式和参数表达式都不可计时。在每个tick中出现的事件是由register_tick_function() 来指定的,注意每个 tick 中可以出现多个事件 更详细的内容,可查看官方文档:https://www.php.net/manual/zh/control-structures.declare.php

<?php
declare(ticks=1);//每执行一条时,触发register_tick_function()注册的函数
$a=1;//在注册之前,不算
function test(){//定义一个函数echo "执行\n";
}
register_tick_function('test');//该条注册函数会被当成低级语句被执行
for($i=0;$i<=2;$i++){//for算一条低级语句$i=$i;//赋值算一条
}

输出:六个“执行”
pcntl_signal
pcntl_signal,安装一个信号处理器

 pcntl_signal ( int $signo , callback $handler [, bool $restart_syscalls = true ] ) : bool

函数pcntl_signal()为signo指定的信号安装一个新的信号处理器

 declare(ticks = 1);
pcntl_signal(SIGINT,function(){echo "你按了Ctrl+C".PHP_EOL;
});
while(1){sleep(1);//死循环运行低级语句
}

输出:当按Ctrl+C之后,会输出“你按了Ctrl+C”
posix_kill
posix_kill,向进程发送一个信号

posix_kill ( int $pid , int $sig ) : bool
第一个参数为进程ID,第二个参数为你要发送的信号

a.php

<?php
declare(ticks = 1);
echo getmypid();//获取当前进程id
pcntl_signal(SIGINT,function(){echo "你给我发了SIGINT信号";
});
while(1){sleep(1);
}

b.php

<?php
posix_kill(执行1.php时输出的进程id, SIGINT);
pcntl_signal_dispatch
pcntl_signal_dispatch,调用等待信号的处理器

pcntl_signal_dispatch ( void ) : bool
函数pcntl_signal_dispatch()调用每个等待信号通过pcntl_signal()安装的处理器

 <?php
echo "安装信号处理器...\n";
pcntl_signal(SIGHUP,  function($signo) {echo "信号处理器被调用\n";
});
echo "为自己生成SIGHUP信号...\n";
posix_kill(posix_getpid(), SIGHUP);
echo "分发...\n";
pcntl_signal_dispatch();
echo "完成\n";
?>

输出:
安装信号处理器…
为自己生成SIGHUP信号…
分发…
信号处理器被调用
完成
pcntl_async_signals()

异步信号处理,用于启用无需 ticks (这会带来很多额外的开销)的异步信号处理。(PHP>=7.1)

 <?php
pcntl_async_signals(true); // turn on async signalspcntl_signal(SIGHUP,  function($sig) {echo "SIGHUP\n";
});posix_kill(posix_getpid(), SIGHUP);

输出:
SIGHUP
三、PHP中处理信号量的方式
前边我们知道我们可以通过declare(ticks=1)pcntl_signal组合的方式监听信号,即每一条PHP低级语句,就会检查一次当前进程是否有未处理的信号,这其实是十分耗性能的。

pcntl_signal的实现原理是,触发信号后先将信号加入一个队列中。然后在PHP的ticks回调函数中不断检查是否有信号,如果有信号就执行PHP中指定的回调函数,如果没有则跳出函数。

 PHP_MINIT_FUNCTION(pcntl)
{php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);php_add_tick_function(pcntl_signal_dispatch TSRMLS_CC);return SUCCESS;
}

在PHP5.3之后,有了 pcntl_signal_dispatch 函数。这个时候将不在需要declare,只需要在循环中增加该函数,就可以调用信号通过了:

 <?php
echo getmypid();//获取当前进程id
pcntl_signal(SIGUSR1,function(){echo "触发信号用户自定义信号1";
});
while(1){pcntl_signal_dispatch();sleep(1);//死循环运行低级语句
}

大家都知道PHP的ticks=1表示每执行1行PHP代码就回调此函数。实际上大部分时间都没有信号产生,但ticks的函数一直会执行。如果一个服务器程序1秒中接收1000次请求,平均每个请求要执行1000行PHP代码。那么PHP的pcntl_signal,就带来了额外的 1000 * 1000,也就是100万次空的函数调用。这样会浪费大量的CPU资源。比较好的做法是去掉ticks,转而使用pcntl_signal_dispatch,在代码循环中自行处理信号。 pcntl_signal_dispatch 函数的实现:

 void pcntl_signal_dispatch()
{//.... 这里略去一部分代码,queue即是信号队列while (queue) {if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {ZVAL_NULL(&retval);ZVAL_LONG(&param, queue->signo);/* Call php signal handler - Note that we do not report errors, and we ignore the return value *//* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */call_user_function(EG(function_table), NULL, handle, &retval, 1, &param TSRMLS_CC);zval_ptr_dtor(&param);zval_ptr_dtor(&retval);}next = queue->next;queue->next = PCNTL_G(spares);PCNTL_G(spares) = queue;queue = next;}
}

但是上边这种,也有个恶心的地方就是,它得放在死循环中。PHP7.1之后出来了一个完成异步的信号接收并处理的函数: pcntl_async_signals

 <?php
//a.php
echo getmypid();
pcntl_async_signals(true);//开启异步监听信号
pcntl_signal(SIGUSR1,function(){echo "触发信号";posix_kill(getmypid(),SIGSTOP);
});
posix_kill(getmypid(),SIGSTOP);//给进程发送暂停信号//b.php
posix_kill(文件1进程, SIGCONT);//给进程发送继续信号
posix_kill(文件1进程, SIGUSR1);//给进程发送user1信号
通过pcntl_async_signals方法,就不用再写死循环了。

监听信号的包:

composer require rain-life/monitor-signal

php进程学习(一)相关推荐

  1. linux pipe 命名管道,linux 进程学习笔记-named pipe (FIFO)命名管道

    与"无名管道"不同的是,FIFO拥有一个名称来标志它,所谓的名称实际上就是一个路径,比如"/tmp/my_fifo",其对应到磁盘上的一个管道文件,如果我们用f ...

  2. 在Linux系统下实现进程,Linux进程学习(一)之Linux进程的基本知识和实现

    最近一周学习了Linux 进程编程的知识,现对其总结如下. 在第一部分中我们先对进程的基本概念以及在Linux 中是如何来现实进程的进行介绍 Tiger-John说明 : 许多人在学习中只注重如何编程 ...

  3. Linux进程学习(孤儿进程和守护进程)

    孤儿进程和守护进程 通过前面的学习我们了解了如何通过fork()函数和vfork()函数来创建一个进程.现在 我们继续深入来学习两个特殊的进程:孤儿进程和守护进程 一.孤儿进程 1.什么是 孤儿进程 ...

  4. Android9.0(Pie) system_server进程学习

    0.引言 在上篇文章<Zygote--Android系统中java世界的受精卵>中,我们提到了zygote的一个关键动作,那就是fork出system_server进程.这篇文章我们就来详 ...

  5. Python进程学习笔记-进程创建fork

    1. 进程 VS 程序 编写完毕的代码,在没有运行的时候,称之为程序 正在运行着的代码,就成为进程 进程,除了包含代码以外,还有需要运行的环境等,所以和程序是有区别的. 2. fork( ) Pyth ...

  6. linux中怎样获得进程描述符,linux进程学习-进程描述符,控制块

    datepicker使用 JqueryUI作为一个优秀的前端库,被广泛的应用在项目中.之前做的一个排班考勤系统,跟时间打交道较多,对时间控件做过一些对比,觉得jqueryUI里的这个datepicke ...

  7. Linux 进程学习(四)------ sigaction 函数

    转自:http://www.cnblogs.com/wblyuyang/archive/2012/11/13/2768923.html 使用 sigaction 函数:  signal 函数的使用方法 ...

  8. Python进程学习笔记-multiprocessing模块

    如果你打算编写多进程的服务程序,Unix/Linux无疑是正确的选择.由于Windows没有fork调用,难道在Windows上无法用Python编写多进程的程序? 由于Python是跨平台的,自然也 ...

  9. 进程学习:进程间通信(传统通信方式)1.无名管道

    无名管道的特点: 1.适用场景:只能用于具有亲缘关系的两个进程之间: 2.通信模式:半双工模式,具有固定的读端(0)和写端(1): 3.读写方式:用文件io,不支持lseek: 4.读阻塞:当管道中无 ...

最新文章

  1. Masking GAN pytorch
  2. 从算法到硬件,一文读懂2019年 AI如何演进
  3. C语言按要求打印数组
  4. windows自带反编译chm文件
  5. 获取数据库中的所有表
  6. GDB调试——常用命令
  7. SAP Spartacus里使用injection token提供默认配置的一个例子
  8. php 类学习,php的类学习(一)
  9. 【BZOJ2588】Count on a tree,主席树维护链+ST表求LCA
  10. Linux/Documentations: Kernel Livepatching
  11. 吃透web前端秘籍,来听听大佬是怎么说的
  12. mysql数据库中的分组查询语句_详解MySQL中的分组查询与连接查询语句
  13. 华为HCNA之PPP认证实验
  14. STM32高速脉冲发波方案
  15. Jieba中文分词 (二) ——词性标注与关键词提取
  16. Android 模块化总结
  17. 【SuperMap】SuperMap.Geometry转GeoJSON
  18. 网点分布图怎么做,用地图制作客户分布图
  19. selenium自动化测试环境搭建及启动safair浏览器(Mac)
  20. css如何设置滚动条,设置滚动条需要用到的参数

热门文章

  1. matlab保存变量的值,怎么不能保存之前的变量值?求解
  2. native react 图片多选_开源一个图片组件 react-native-border-radius-image
  3. 微擎任意消息该公众号提供的服务器,该公众号提供的服务出现故障,请稍后再试...
  4. java线程死亡_java – 如何暂停main()直到所有其他线程死亡?
  5. 近几年,关于基于Imagenet数据集图像分类的模型总结
  6. 八十三、React简书项目:Styled-Components 与 Reset.css 的结合使用,完成Header布局
  7. 关于浏览器跨域请求的相关原理实现--很经典的博客
  8. 科研实习 | 约翰霍普金斯大学Alan Yuille教授招收计算机视觉暑期科研实习生
  9. Back-Training: 用于问题生成和段落检索的全新领域自适应方法
  10. 一文详解支持向量机(SVM)