1. 什么是Volatile
在PHP的pthreads v3扩展中,Volatile是一个类,可以在多个线程之中被共享并且进行原子操作,即每个操作的结果可以预测和保证。
Volatile操作并不保证线程安全,因为其并没有做理论的做法保证在竞态条件之中得到正确的结果。但是经过测试,在大多数情况下它都可以工作得非常好。
2. Volatile 的使用方法示例
2.1 原子操作
下面的例子展示了一个计数器类,可以通过count方法对该计数器进行原子操作。其中,Volatile::atomic对一个Volatitle对象进行原子操作,使用时请确保您在进行原子操作的锁。
class Counter
{
public volatile $count = 0;
public function increment()
{
Volatile::atomic($this->count, function(&$count){
++$count;
});
}
public function get()
{
return $this->count;
}
}
2.2 多个线程操作同一个计数器
下面的代码示例演示了4个线程如何对同一个计数器进行操作,并最终输出计数器的结果。
$counter = new Counter();
$workers = [];
foreach (range(1, 4) as $index) {
$worker = new class($counter) extends Thread {
public $counter;
public function __construct(Counter $counter) {
$this->counter = $counter;
}
public function run() {
foreach (range(1, 100) as $_) {
$this->counter->increment();
}
}
};
$worker->start();
$workers[] = $worker;
}
foreach ($workers as $worker) {
$worker->join();
}
echo 'Counter: ' . $counter->get() . PHP_EOL;
由上面的代码可以得出,四个线程不同时对count进行访问,但是可以通过Volatile的原子特性进行保护,达到了非常好的效果。
2.3 获取一个对象的属性值 (非原子操作)
下面的代码示例展示了如何获取一个对象的属性值:
class MyClass
{
public volatile $testProperty = null;
}
$obj = new MyClass();
// Get the value of $obj->testProperty
$currentValue = $obj->testProperty;
由于没有使用Volatile::atomic方法,因此这个例子并不是原子操作。
2.4 设置一个对象的属性值 (非原子操作)
下面的代码示例展示了如何设置一个对象的属性值:
class MyClass
{
public volatile $testProperty = null;
}
$obj = new MyClass();
// Set the value of $obj->testProperty
$obj->testProperty = 'new value';
由于没有使用Volatile::atomic方法,因此这个例子并不是原子操作。