Since PHP scripts aren't multi-threaded, I don't believe critical-sections are relevant. I agree that you have a race condition because multiple instances are run in parallel, but a critical section won't solve your problem.
If you're using a file-based session handler, you can try a basic flock()
. If using a database, you can try using the engine's own (preferably, row-level) locking mechanism. If using memcached, you can try implementing a distributed lock system.
You won't want to apply a lock too broadly. You'll want something as granular as possible (tied to the session ID, perhaps). If you attempt to serialize all session behavior, you'll introduce a massive bottleneck.
In the database world (and elsewhere), optimistic "locks" are often all you need. They involve a simple counter that is incremented. If the count is "off," (collision) the record isn't updated and you can re-fetch and apply your differences as appropriate. It's an UPDATE table WHERE count = lastcount
type thing combined with retry. This often does the trick.
Of course, you can use file locking, SYSV semaphores (sparingly) and a variety of other methods to achieve this goal. Just remember, this sounds like a race condition, but it has nothing to do with threads.