gpt4 book ai didi

php - 使用 pthreads 在 PHP 中的竞争条件

转载 作者:行者123 更新时间:2023-12-03 12:45:46 26 4
gpt4 key购买 nike

我有一些小代码演示了如何在多线程 PHP 中执行竞争条件。

我的想法是我和我的 friend 共用一个锅做饭。如果锅里已经有食材,则锅不能煮。

锅类:

class Pot
{
public $id;
function __construct()
{
$this->id = rand();
}

public $ingredient;

public function cook($ingredient, $who, $time){
if ($this->ingredient==null){
$this->ingredient = $ingredient;
print "pot".$this->id.'/'.$who." cooking ".$this->ingredient. " time spent: ".$time." \n";
sleep($time);
print "pot".$this->id.'/'.$who." had flush ingredient \n";
$this->ingredient = null;

}else{
throw new Exception("Pot still cook ".$this->ingredient);
}
}
}

同学:

class Friend extends Thread
{
/**
* @var Pot
*/
protected $pot;

function run() {
Cocking::cleanVegetable("Friend");
print "Friend will cook: \n";
$this->pot->cook("vegetable", 'Friend',4);
Cocking::digVegetable("Friend");
}

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

我的类:

class My
{
/**
* @var Pot
*/
private $pot;
public function doMyJob(){
Cocking::cleanRice("I");
print "I will cook: \n";
$this->pot->cook("rice", "I",10);


Cocking::digRice("I");
}

public function playGame(Friend $friend){
print "play with friend \n";
}

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

上课:

<?php


class Cocking
{
static function cleanRice($who){
print $who." is cleaning rice \n";
}
static function cleanVegetable($who){
print $who."is cleaning vegetable \n";
}


static function digRice($who){
print $who." is digging rice \n";
}

static function digVegetable($who){
print $who." is digging vegetable \n";
}
}

运行脚本:

require_once "Friend.php";
require_once "My.php";
require_once "Cocking.php";
require_once "Pot.php";

$pot = new Pot();
$friend = new Friend($pot);
$my = new My($pot);

$friend->start();
$my->doMyJob();
$friend->join();
$my->playGame($friend);

这太奇怪了以至于输出永远不会抛出异常?我认为这总是会发生。

root@e03ed8b56f21:/app/RealLive# php index.php
Friendis cleaning vegetable
I is cleaning rice
Friend will cook:
I will cook:
pot926057642/I cooking rice time spent: 10
pot926057642/Friend cooking vegetable time spent: 4
pot926057642/Friend had flush ingredient
Friend is digging vegetable
pot926057642/I had flush ingredient
I is digging rice
play with friend

Pot 是我用过的,不过我 friend 还能用它来煮菜。这么变态?我希望结果是:

Friend will cook:
I will cook:
pot926057642/I cooking rice time spent: 10
PHP Fatal error: Uncaught Exception: Pot still cook rice in /app/RealLive/Pot.php:23
Stack trace:
#0 /app/RealLive/My.php(14): Pot->cook('rice', 'I', 10)
#1 /app/RealLive/index.php(12): My->doMyJob()
#2 {main}
thrown in /app/RealLive/Pot.php on line 23

ps:我的环境是

PHP 7.0.10 (cli) (built: Apr 30 2019 21:14:24) ( ZTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies

非常感谢您的评论。

最佳答案

您的假设似乎是您的 if 条件后跟直接成员分配总是需要一次性运行。但是,Friend 完全有可能在线程中运行这行代码:

if ($this->ingredient==null){

... 并结束继续,但在它到达下一行分配 $this->ingredient 之前,执行切换回 My/main thread,它也到达这一行:

if ($this->ingredient==null){

因为 Friend 已经通过了 if 但还没有开始实际分配成分,所以 My 现在也可以通过了。无论接下来运行什么都不重要,您现在可以让两个线程同时访问 cooking 锅。

附加更正/注意:该示例似乎也不起作用,因为 $this->ingredient 不是 Volatile。然而,这仍然会使它容易出现上述竞争条件,因此仍然是一个坏主意。

如何正确地做到这一点:您确实需要使用互斥体或同步部分来进行正确的同步。此外,永远不要假设线程不能在任何地方的中间切换,包括任何两行,例如 if 后跟作为一对的变量赋值。

这是关于同步部分的 PHP 文档:https://www.php.net/manual/en/threaded.synchronized.php

关于php - 使用 pthreads 在 PHP 中的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64302356/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com