在新线程中传递和读取属性(pthreads)

时间:2015-08-25 21:06:42

标签: php pthreads

我有使用类Model的类程序。现在我需要在多个线程中运行Program,但它不能正常工作。我的代码是:

$connection = new PDO('mysql:host=localhost;dbname=x', 'y', 'z');

class Model {
    public $connection;
    public function setConnection(PDO $connection) {
        $this->connection = $connection;
        //echo get_class($this->connection)." | setConnection<br />\n"; //returns PDO
    }
}

class Program {
    public $model;
    public function setModel(Model $model) {
        $this->model = $model;
    }
    public function run() {
        echo get_class($this->model->connection)." | run<br />\n";
    }
}

class ProgramThread extends Thread {
    public $i;
    public $program;

    public function __construct($i, Program $program, PDO $connection)
    {
        $this->i = $i;
        $this->program = $program;
        $this->program->model->setConnection($connection);
        echo get_class($this->program->model->connection)." | __construct<br />\n";
    } 

    public function run()
    {
        $this->program->run();
    }
}
//
$program = new Program();
$model = new Model;
$program->setModel($model);

现在我在多个线程中运行它:

$threads = [];
foreach (range(1, 1) as $i) { //only 1 thread for example
    $threads[$i] = new ProgramThread($i, clone $program, clone $connection);
    $threads[$i]->start();
}

它返回错误的类名Program和ProgramThread而不是预期的PDO。

Program | run
ProgramThread | __construct

当我删除&#34;扩展线程&#34;从第一个代码开始运行:

$pt = new ProgramThread(1, clone $program, clone $connection);
$pt->run();

它返回正确的结果:

PDO | __construct
PDO | run

问题出在哪里?

以下是具有相同输出的简单示例:

class Program {
    public $connection;
    public function run() {
        echo get_class($this->connection)." | run<br />\n";
    }
}
class Connection { //unserializable class
}
class ProgramThread extends Thread { //try deleting  "extends Thread"
    public $program;
    public function __construct(Program $program, Connection $connection)
    {
        $this->program = $program;
        $this->program->connection = $connection;
        echo get_class($this->program->connection)." | __construct<br />\n";
    } 

    public function run()
    {
        $this->program->run();
    }
}

$connection = new Connection();
$program = new Program;

$pt = new ProgramThread(clone $program, clone $connection);
$pt->run();

1 个答案:

答案 0 :(得分:1)

您尝试做的事情有几个问题:

  • PDO是依赖资源运作的对象。
  • 线程对象的属性与其他对象不同。

正式不支持资源,您要做的是为每个线程使用PDO对象,仅将连接参数传递给线程。即使偶然的驱动程序碰巧使用pthreads,使用它也不安全,你必须为每个线程创建一个连接。

<?php
class Program {
    public function run() {
        echo get_class($this->connection)." | run<br />\n";
    }
}

class Connection {}

class ProgramThread extends Thread {

    public function __construct(Program $program, Connection $connection)
    {
        $program->connection = $connection;

        $this->program = $program;

        echo get_class($this->program->connection)." | __construct<br />\n";
    } 

    public function run()
    {
        $this->program->run();
    }
}

$connection = new Connection();
$program = new Program;

$pt = new ProgramThread(clone $program, clone $connection);
$pt->run();

请注意,这会给出您期望的输出,因为在序列化对象以进行存储之前已设置连接。

这仍然是一个可怕的代码,当您为PDO交换示例对象时,它不会像您期望的那样运行。

<?php
class PDOWorker extends Worker {

    public function __construct(array $config) {
        $this->config = $config;
    }

    public function run() {
        self::$connection = 
            new PDO(...$this->config);
    }

    private $config;

    public static $connection;
}

$pool = new Pool(4, PDOWorker::class, [["sqlite:example.db"]]);

while (@$i++<10) $pool->submit(new class extends Collectable {
    public function run() {
        if (PDOWorker::$connection) {
            printf("Got connection from %s in Thread #%lu\n",
                get_class($this->worker),
                Thread::getCurrentThreadId());
        }

    }
});

$pool->shutdown();
?>

将输出如下内容:

Got connection from PDOWorker in Thread #140458223204096
Got connection from PDOWorker in Thread #140458210621184
Got connection from PDOWorker in Thread #140458234603264
Got connection from PDOWorker in Thread #140458223204096
Got connection from PDOWorker in Thread #140458223204096
Got connection from PDOWorker in Thread #140458234603264
Got connection from PDOWorker in Thread #140458210621184
Got connection from PDOWorker in Thread #140458198038272
Got connection from PDOWorker in Thread #140458198038272

PHP7代码,因为世界正在发展......如果你想看PHP5代码,你可以向后推断......

注意PDO对象如何存储在静态类成员中,这些对象被pthreads视为线程本地,并且从不被序列化。因此,每个线程都有自己的连接,一切都按预期运行,并且您正在按预期使用驱动程序。