php Swoole进程锁

2021-10-03

请勿在onReceive等回调函数中创建锁,否则内存会持续增长,造成内存泄漏;协程中无法使用锁;不要在lock和unlock操作中间使用可能引起协程切换的API

$lock_types = [
	SWOOLE_MUTEX,	  // 互斥锁
	SWOOLE_RWLOCK,	  // 读写锁
	SWOOLE_SPINLOCK,  // 自旋锁
];

互斥锁

use Swoole\Process;
use Swoole\Lock;

// 创建锁
$lock = new Lock(SWOOLE_MUTEX);

$worker1 = new Process(function ($process) use ($lock) {
    // 加锁,如果有其他进程持有锁,那这里将进入阻塞,直到持有锁的进程 unlock() 释放锁。获取独占锁,在独占锁加锁时,其他进程无法再进行任何加锁操作,包括读锁
	if ($lock->lock()) {
		echo "{$process->pid}:锁" . PHP_EOL;
		sleep(3);
		// 释放锁
		$lock->unlock();
		echo "{$process->pid}:释放" . PHP_EOL;
	}
});
$worker1->start();

$worker2 = new Process(function ($process) use ($lock) {
	if ($lock->lock()) {
		echo "{$process->pid}:锁" . PHP_EOL;
		sleep(3);
		$lock->unlock();
		echo "{$process->pid}:释放" . PHP_EOL;
	}
});
$worker2->start();

while ($status = Process::wait(true)) {
    echo "Recycled #{$status['pid']}, code={$status['code']}, signal={$status['signal']}" . PHP_EOL;
}

互斥锁超时

use Swoole\Process;
use Swoole\Lock;

// 创建锁
$lock = new Lock(SWOOLE_MUTEX);

$worker1 = new Process(function ($process) use ($lock) {
    // 加锁并设置超时时间,获取独占锁,在独占锁加锁时,其他进程无法再进行任何加锁操作,包括读锁;只有SWOOLE_MUTEX类型可以使用
	if ($lock->lockwait(2)) {
		echo "{$process->pid}:锁" . PHP_EOL;
		sleep(3);
		// 释放锁
		$lock->unlock();
		echo "{$process->pid}:释放" . PHP_EOL;
	} else {
		echo "{$process->pid}:获取锁超时" . PHP_EOL;
	}
});
$worker1->start();

$worker2 = new Process(function ($process) use ($lock) {
	if ($lock->lockwait(2)) {
		echo "{$process->pid}:锁" . PHP_EOL;
		sleep(3);
		// 释放锁
		$lock->unlock();
		echo "{$process->pid}:释放" . PHP_EOL;
	} else {
		echo "{$process->pid}:获取锁超时" . PHP_EOL;
	}
});
$worker2->start();

while ($status = Process::wait(true)) {
    echo "Recycled #{$status['pid']}, code={$status['code']}, signal={$status['signal']}" . PHP_EOL;
}

互斥锁非阻塞

use Swoole\Process;
use Swoole\Lock;

// 创建锁
$lock = new Lock(SWOOLE_MUTEX);

$worker1 = new Process(function ($process) use ($lock) {
    // 加锁但不阻塞,获取独占锁,在独占锁加锁时,其他进程无法再进行任何加锁操作,包括读锁
	if ($lock->trylock()) {
		echo "{$process->pid}:锁" . PHP_EOL;
		sleep(3);
		// 释放锁
		$lock->unlock();
		echo "{$process->pid}:释放" . PHP_EOL;
	} else {
		echo "其他进程获得锁,{$process->pid}:获取不到" . PHP_EOL;
	}
});
$worker1->start();

$worker2 = new Process(function ($process) use ($lock) {
	if ($lock->trylock()) {
		echo "{$process->pid}:锁" . PHP_EOL;
		sleep(3);
		// 释放锁
		$lock->unlock();
		echo "{$process->pid}:释放" . PHP_EOL;
	} else {
		echo "其他进程获得锁,{$process->pid}:获取不到" . PHP_EOL;
	}
});
$worker2->start();

while ($status = Process::wait(true)) {
    echo "Recycled #{$status['pid']}, code={$status['code']}, signal={$status['signal']}" . PHP_EOL;
}

读写锁-只读锁

use Swoole\Process;
use Swoole\Lock;

// 创建锁
$lock = new Lock(SWOOLE_MUTEX);

$worker1 = new Process(function ($process) use ($lock) {
    // 加只读锁;在持有读锁的过程中,其他进程依然可以获得读锁,可以继续发生读操作;只有SWOOLE_RWLOCK类型可以使用
	if ($lock->lock_read()) {
		echo "{$process->pid}:锁" . PHP_EOL;
		sleep(3);
		// 释放锁
		$lock->unlock();
		echo "{$process->pid}:释放" . PHP_EOL;
	}
});
$worker1->start();

$worker2 = new Process(function ($process) use ($lock) {
	if ($lock->lock_read()) {
		echo "{$process->pid}:锁" . PHP_EOL;
		sleep(3);
		// 释放锁
		$lock->unlock();
		echo "{$process->pid}:释放" . PHP_EOL;
	}
});
$worker2->start();

while ($status = Process::wait(true)) {
    echo "Recycled #{$status['pid']}, code={$status['code']}, signal={$status['signal']}" . PHP_EOL;
}

读写锁-只读锁-非阻塞

use Swoole\Process;
use Swoole\Lock;

// 创建锁
$lock = new Lock(SWOOLE_MUTEX);

$worker1 = new Process(function ($process) use ($lock) {
    // 加只读锁但不阻塞,在持有读锁的过程中,其他进程依然可以获得读锁,可以继续发生读操作
	if ($lock->trylock_read()) {
		echo "{$process->pid}:锁" . PHP_EOL;
		sleep(3);
		// 释放锁
		$lock->unlock();
		echo "{$process->pid}:释放" . PHP_EOL;
	} else {
		echo "其他进程获得锁,{$process->pid}:获取不到" . PHP_EOL;
	}
});
$worker1->start();

$worker2 = new Process(function ($process) use ($lock) {
	if ($lock->trylock_read()) {
		echo "{$process->pid}:锁" . PHP_EOL;
		sleep(3);
		// 释放锁
		$lock->unlock();
		echo "{$process->pid}:释放" . PHP_EOL;
	} else {
		echo "其他进程获得锁,{$process->pid}:获取不到" . PHP_EOL;
	}
});
$worker2->start();

while ($status = Process::wait(true)) {
    echo "Recycled #{$status['pid']}, code={$status['code']}, signal={$status['signal']}" . PHP_EOL;
}

 

{/if}