I got the following two functions that I use to lock a Redis key. I am trying to prevent concurrency execution of a block of code using Redis. So what I do is use the following functions in such a way that they prevent the execution of the same code by different threads.
lockRedisKey("ABC");
CODE THAT I DON'T WANT TO RUN CONCURRENTLY!
unlockRedisKey("ABC");
Unfortunately, it doesn’t seem to work and causes an infinitely loop at lockRedisKey() until exit_time is reached. What could be wrong?
static public function lockRedisKey($key, $value = "true") {
$redis = RedisClient::getInstance();
$time = microtime(true);
$exit_time = $time + 10;
$sleep = 10000;
do {
// Lock Redis with PX and NX
$lock = $redis->setnx("lock:" . $key, $value);
if ($lock == 1) {
$redis->expire("lock:" . $key, "10");
return true;
}
usleep($sleep);
} while (microtime(true) < $exit_time);
return false;
}
static public function unlockRedisKey($key) {
$redis = RedisClient::getInstance();
$redis->del("lock:" . $key);
}
I’m aware that I might be facing deadlocks, so I decided to use transactions, but I continue to face the issue.
static public function lockRedisKey($key, $value = "true") {
$redis = RedisClient::getInstance();
$time = microtime(true);
$exit_time = $time + 10;
$sleep = 10000;
do {
// Lock Redis with PX and NX
$redis->multi();
$redis->set('lock:' . $key, $value, array('nx', 'ex' => 10));
$ret = $redis->exec();
if ($ret[0] == true) {
return true;
}
usleep($sleep);
} while (microtime(true) < $exit_time);
return false;
}
static public function unlockRedisKey($key) {
$redis = RedisClient::getInstance();
$redis->multi();
$redis->del("lock:" . $key);
$redis->exec();
}
3
Answers
The locking is working fine. It's just the code between the locking that is crashing and causing the lock not to be released :-)
First of all, PHP isn’t async script language as JS f.e. You haven’t any control on the script execution ordering, so it means you can’t run code that below
lockRedisKey()
call in concurent way.I assume you’re not completely understand what usleep function is actually doing, it’s just delay process and not postpone it, so it just blocks process for
$sleep
time and after this continue script execution. So you’re not performing concurrent write by calling your script.Your ‘exit_time’ is too small.
I think the meaning of ‘$exit_time = $time + 10;’ is to turn it off after 10 seconds.
However, the set time is microtime.
Maybe you can replace ‘$exit_time = $time + 10;’ with ‘$exit_time = $time + 100000;’.
Written by Google Translate