swoole / swoole-src

🚀 Coroutine-based concurrency library for PHP
https://www.swoole.com
Apache License 2.0
18.42k stars 3.16k forks source link

swoole进程中使用协程死锁问题 #5017

Closed suuhui closed 1 year ago

suuhui commented 1 year ago

现象

swoole进程中,创建协程,使用协程客户端从服务端收取消息,结果报错[FATAL ERROR]: all coroutines (count: 1) are asleep - deadlock!

简化代码

<?php

use Swoole\Process;

class DeadLock
{
    public function startProcess()
    {
        $t = new Swoole\Process(function () {
            swoole_async_set(['enable_coroutine' => true]);
            go(function (){
                for (; ;) {
                    Swoole\Coroutine\System::sleep(1);
                    var_dump('dd');
                }
            });
        });
        $t->start();
    }
}

$proc = new Process(function () {
    swoole_async_set(['enable_coroutine' => false]);
    $cls = new DeadLock();
    //$cls->startProcess(); 1. 此处调用不报错
    \Swoole\Timer::after(1000, function () use ($cls) {
        $cls->startProcess(); //2. 此处调用会报错
    });
});
$proc->start();

环境信息

php版本:7.2.34 swoole版本:

Swoole => enabled
Author => Swoole Team <team@swoole.com>
Version => 4.8.9
Built => May 10 2022 20:17:44
coroutine => enabled with boost asm context
kqueue => enabled
rwlock => enabled
pcre => enabled
zlib => 1.2.11
async_redis => enabled

Directive => Local Value => Master Value
swoole.enable_coroutine => On => On
swoole.enable_library => On => On
swoole.enable_preemptive_scheduler => Off => Off
swoole.display_errors => On => On
swoole.use_shortname => On => On
swoole.unixsock_buffer_size => 262144 => 262144
NathanFreeman commented 1 year ago
<?php

use Swoole\Process;
use Swoole\Event;

class DeadLock
{
    public function startProcess()
    {
        $t = new Swoole\Process(function () {
            swoole_async_set(['enable_coroutine' => true]);
            go(function (){
                for (; ;) {
                        Swoole\Coroutine\System::sleep(1);
                        var_dump('dd');
                }
            });
            Swoole\Event::wait();
        });
        $t->start();
        Process::wait();
    }
}

$proc = new Process(function () {
    swoole_async_set(['enable_coroutine' => false]);
    $cls = new DeadLock();
    //$cls->startProcess();
    \Swoole\Timer::after(1000, function () use ($cls) {
            $cls->startProcess();
    });
    Event::wait();
});
var_dump($proc->start());
Process::wait();

你可以试试这么写,现在是推荐在文件末尾加上Swoole\Event::wait()启动事件机制。

suuhui commented 1 year ago

@NathanFreeman 这样写就可以了,能讲解下为什么不加Swoole\Event::wait()就报错吗

NathanFreeman commented 1 year ago

这个其实是因为如果不加Swoole\Event::wait(),依靠php_swoole_register_shutdown_function注册的函数执行事件机制的话在一些特定的场景下总有一些奇奇怪怪的问题。