口袋Mine / snooze
适用于使用 pthreads 扩展的代码的线程通知管理库
0.5.0
2023-05-22 23:43 UTC
Requires
- php-64bit: ^8.1
- ext-pmmpthread: ^6.0
Requires (Dev)
- phpstan/extension-installer: ^1.0
- phpstan/phpstan: 1.10.3
- phpstan/phpstan-strict-rules: ^1.0
README
适用于使用 pthreads 扩展的代码的事件驱动线程通知管理库
使用场景
ext-pthreads 当前无法方便地同时等待来自多个线程的通知。这个库允许你使用 SleeperHandler
来实现这一点。
每个线程都必须有自己的 SleeperNotifier
(由于它们是线程安全的,你可以在线程之间共享通知器,但建议不要这样做)。线程应在它的 SleeperNotifier
上调用 wakeupSleeper()
,这将导致等待 SleeperHandler
的线程醒来并处理传递的任何通知。
这与在套接字或文件描述符数组上使用 select()
系统调用类似,但使用的是线程。
示例
class NotifyingThread extends \pmmp\thread\Thread{ public function __construct( private \pocketmine\snooze\SleeperHandlerEntry $sleeperEntry, private \pmmp\thread\ThreadSafeArray $buffer ){} public function run() : void{ $stdin = fopen('php://stdin', 'r'); $notifer = $this->sleeperEntry->createNotifier(); while(true){ echo "Type something and press ENTER:\n"; //do whatever you're doing $line = fgets($stdin); //blocks until the user enters something //add the line to the buffer $this->buffer[] = $line; //send a notification to the main thread to tell it that we read a line //the parent thread doesn't have to be sleeping to receive this, it'll process it next time it tries to go //back to sleep //if the parent thread is sleeping, it'll be woken up to process notifications immediately. $notifer->wakeupSleeper(); } } } $sleeper = new \pocketmine\snooze\SleeperHandler(); $buffer = new \pmmp\thread\ThreadSafeArray(); $sleeperEntry = $sleeper->addNotifier(function() use($buffer) : void{ //do some things when this notifier sends a notification echo "Main thread got line: " . $buffer->shift(); }); $thread = new NotifyingThread($sleeperEntry, $buffer); $thread->start(); while(true){ $start = microtime(true); //do some work that you do every tick //process any pending notifications, then try to sleep 50ms until the next tick //this may wakeup at any time to process received notifications //if it wakes up and there is still time left to sleep before the specified time, it will go back to sleep again //until that time, guaranteeing a delay of at least this amount //if there are notifications waiting when this is called, they'll be processed before going to sleep $sleeper->sleepUntil($start + 0.05); } while(true){ //alternatively, if you want to only wait for notifications and not tick: //but from the pthreads rulebook, only ever wait FOR something! //this will wait indefinitely until something wakes it up, and then return immediately $sleeper->sleepUntilNotification(); } $thread->join(); //Unregister the notifier when you're done with it $sleeper->removeNotifier($sleeperEntry->getNotifierId());