Что ж, если вы говорите об одной операции, она будет атомарной (в зависимости от того, как работает APC). Либо все это будет написано, либо ничего не будет ...
Если вы говорите о нескольких операциях (как при обновлении каждого места, на которое ссылается объект), то нет ничего встроенного, чтобы предотвратить состояние гонки. Вместо этого вам нужно реализовать какую-то блокировку, чтобы другие процессы не пытались обновить эти данные.
Один из способов сделать это - «заблокировать» каждый кэшированный элемент, записав специальный блокированный «кэшированный» элемент в известный идентификатор перед началом операции (представьте себе блокировку на уровне строк в базах данных).
Итак, предполагая массив затронутых идентификаторов кэша:
function getLocks($cacheIds) {
$locked = array();
foreach ($cacheIds as $cacheId) {
if (apc_exists($cacheId . '_locked')) {
//Another process has this id locked, clear all locks and return
foreach ($locked as $id) apc_delete($id . '_locked');
return false;
} else {
//Use a short TTL to prevent issues if this process dies
apc_store($cacheId . '_locked', 60);
$locked[] = $cacheId;
}
}
return true;
}
function releaseLocks($cacheIds) {
foreach ($cacheIds as $cacheId) {
apc_delete($cacheId . '_locked');
}
}
Итак, тогда вы можете просто позвонить:
if (getLocks($cacheIds)) {
//Do your operation here
releaseLocks($cacheIds);
}
Теперь, имейте в виду, что это не предотвращает малую вероятность того, что два процесса будут проверять один и тот же ключ в одно и то же время (и, следовательно, оба возвращают false для apc_exists
, но перезаписывают друг друга). Если это большая проблема, вы должны прочитать о двойной проверке блокировки