echo sprintf("With a mutex, 1 + 1 = %d\n", $shared->withMutex); // 2 } // Without mutex... if (isset($argv[1]) === true) { // for all processes, this condition is true if ($shared->withoutMutexAlreadyCalculated === false) { // a "long" calculation sleep(1); $shared->withoutMutex = $shared->withoutMutex + 1; $shared->withoutMutexAlreadyCalculated = true; } } // With a mutex... if (isset($argv[1]) === true) { $shared->lock(); // Only one process at once can pass between lock and unlock. // So this condition is true only once. if ($shared->withMutexAlreadyCalculated === false) { // a "long" calculation sleep(1); $shared->withMutex = $shared->withMutex + 1; $shared->withMutexAlreadyCalculated = true; } $shared->unlock(); } /* * Explaination : access to $shared->withoutMutexAlreadyCalculated and * $shared->withoutMutex is concurrent : it means, before those variables has * been set by a process, they have been read with the same value several times. * Result of our calculation becomes unexepected.
public function testUnlock() { $file = self::DIR . "/test.sync"; $storage = new StorageFile($file); $sharedA = new SharedMemory($storage); $sharedA->hello = 'world'; $sharedA->lock(1); $sharedA->foo = 'bar'; $sharedA->unlock(); $sharedB = new SharedMemory($storage); try { $test = $sharedB->hello; } catch (\Exception $e) { $this->fail(sprintf("Unexpected exception has been raised: %s.", $e->getMessage())); return; } $this->assertEquals('world', $test); }