in reply to •Re: Logical Conundrum
in thread Logical Conundrum

I've worked this out to something of the following design:
if (locked) { while (locked) { if (unlocked) { lock print unlock break; } } } else { lock print unlock }
The only thing I need to make this work is a flock() test to see if it CAN to an exclusive lock (the lock file is not already locked).

Replies are listed 'Best First'.
•Re: Re: •Re: Logical Conundrum
by merlyn (Sage) on Dec 01, 2003 at 18:38 UTC
    if (unlocked) { lock
    No, you've got a race condition there. Two processes can both see "unlocked" at the same time, then they both "lock" and they think they've got it.

    That's why you need "atomic test and set". There's really no way around it. The thing that checks for unsettedness needs to also set it if it can, in a way that can't be interrrupted or observed by another process/thread/entity. This usually requires operating-system-level locks.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re^3: Logical Conundrum
by Aristotle (Chancellor) on Dec 01, 2003 at 19:05 UTC
    To make merlyn's point clearer, what you need is
    sleep(rand) until lock(exclusive); print close

    The lock() function must return whether it was able to get a lock, and you must not use a separate is_locked() function in this process. Actually, you should never need one at all, because you know when you have the lock and you're not interested in whether someone else has one if you don't have it.

    sleep() is only necessary if your locking function does not block. rand() must be used if this is only one of several locks or other synchronization mechanisms used by multiple processes, because they might otherwise get in a deadlock situation when each process holds a lock on some of the resources but not on others.

    You may also unlock() instead of close() if you know what you're doing, but it has only become safe in recent versions of Perl, and even so it poses the danger that you'll attempt to read data from the file while another process is writing to it. Ideally, you should lock(shared) if you're going to be reading from the file, and the locking mechanism should honour exclusive lock requests from others before your lock degradation request. In that way, no writing process starves, while no reading process gets to read inconsistent data.

    Do not underestimate the complexity of locking. Unfortunately if you don't get it perfect, you might as well not bother at all.

    Makeshifts last the longest.