【发布时间】:2016-11-30 07:27:37
【问题描述】:
我正在使用 libevent 的 PHP Event 类包装器来读取串行端口。我正在使用它来避免缓冲区溢出 - 想法是使用 Event 定期检查端口,以免丢失数据。
我希望事件在设置时会触发,但得出的结论是事件仅在调用 EventBase::loop() 后触发。在这种情况下,当我调用loop() 时,控制流会从我的代码转到 libevent 中的调度程序。最终控制流返回到我的代码在调用循环之后的位置。
我从这种行为中假设我实际上是在调度事件的调度,并且应该定期调用 loop() 以避免我的事件被 CPU 耗尽。
但是在这种情况下,我应该永远无法在之前的 loop() 调用运行时调用 loop(),因为根据上面的解释,控制流要么在我的代码中,要么在 libevent 中,不能同时在两者中.
所以我通过我的代码调用loop()(总共四个 - 我正在摸索中),其中两个产生 libevent 重入警告。
我显然不明白这一点。有人可以帮忙吗?
干杯保罗
<?php
// serial comms defines
define("PORT", "/dev/serial0");
const PORTSETTINGS = array(
'baud' => 9600,
'bits' => 8,
'stop' => 1,
'parity' => 0
);
define("SYN", 170);
define("MSB", 127);
const POLL = 0.1;
/*
** Class Scanner
**
** Manages low level serial comms with the vbus master
**
*/
class Scanner {
private $fd;
private $pkt;
private $state;
private $base;
private $timer;
/*
** __construct()
**
** setup the serial port for reading using dio
** setup a timer to read anything on the serial port frequently
**
*/
function __construct() {
// set up port and state machine
$this->fd = dio_open(PORT, O_RDONLY | O_NOCTTY | O_NONBLOCK);
dio_tcsetattr($this->fd, PORTSETTINGS);
$this->pkt = array();
$this->state = "discard";
// set up timer handler
$this->base = new EventBase();
$this->timer = new Event($this->base, -1, Event::TIMEOUT | Event::PERSIST, array($this, "Tickle"));
$this->timer->addTimer(POLL);
$this->base->loop(EventBase::LOOP_NONBLOCK);
}
function PrintPkt($pkt) {
echo "\n\n".date("H:i:s");
foreach($pkt as $i)
echo " ".dechex($i);
}
/*
** Tickle()
**
** read the serial port, if MSB set discard the packet, else save the packet and then pass for processing
** called by the event timer on a regular basis ie POLL seconds
*/
function Tickle() {
do {
// read the next one and convert to int
$ch = dio_read($this->fd, 1);
$i = ord($ch);
// check for MSB, if set discard to the next packet
if (($i > MSB) && ($i != SYN))
$state="discard";
// if there is nothing on the port it returns 0x0 ie null/false
if ($i) {
if ($i == SYN) {
// we are at the start of a new packet
if (count($this->pkt) > 0) {
if ($this->state === "save")
// this is where we would save the packet but for now we are printing it.
$this->PrintPkt($this->pkt);
// reset for the next packet
$this->pkt = array();
$this->state = "save";
}
}
// save this number
$this->pkt[] = $i;
}
} while ($ch);
// restart the timer
$this->timer->addTimer(POLL);
}
/*
** spin()
**
** call the base loop so that the timer event is serviced
*/
function spin() {
$this->base->loop(EventBase::LOOP_NONBLOCK);
}
}
$c = new Scanner();
echo "setup";
while(1);
// $c->spin();
?>
【问题讨论】:
-
我已经添加了我正在使用的测试代码。我已经采纳了俄语的建议。唯一的变化是底座上的非阻塞标志。这导致没有输出。没有非阻塞标志,它输出正常。目前底部有一个无限循环,最终将被编码以处理已保存在事件回调中的数据包。目的是在端口上没有数据时给予串行处理优先级并执行其他所有操作。
标签: php libevent pecl-event pecl-dio