This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author lechten
Recipients lechten
Date 2013-01-19.19:13:49
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1358622837.13.0.603431337609.issue16998@psf.upfronthosting.co.za>
In-reply-to
Content
Maybe I'm misreading the documentation of multiprocessing.Value and
multiprocessing.sharedctypes.Value.
I thought that access to the value field of Value instances was protected by
locks to avoid lost updates.

Specifically, for multiprocessing.Value(typecode_or_type, *args[, lock]) and
multiprocessing.sharedctypes.Value(typecode_or_type, *args[, lock]) the
documentation states:
> By default the return value is actually a synchronized wrapper for the
> object. [...]
> If lock is True (the default) then a new lock object is created to
> synchronize access to the value. If lock is a Lock or RLock object then that
> will be used to synchronize access to the value. If lock is False then
> access to the returned object will not be automatically protected by a lock,
> so it will not necessarily be “process-safe”.

(By the way, I'm not sure why both, multiprocessing.Value and
multiprocessing.sharedctypes.Value are documented.  They appear to be the same
thing.)

The following tests (also attached as file) show that lost updates may occur
if several instances of multiprocessing.Process increment the same Value that
is passed as args parameter.

def do_inc(integer):
    """Increment integer.value for multiprocessing.Value integer."""
    integer.value += 1

def do_test(notasks):
    """Create notasks processes, each incrementing the same Value.

    As the Value is initialized to 0, its final value is expected to be
    notasks.
    """
    tasks = list()
    integer = multiprocessing.sharedctypes.Value("i", 0)
    for run in range(notasks):
        proc = multiprocessing.Process(target=do_inc, args=(integer,))
        proc.start()
        tasks.append(proc)
    for proc in tasks:
        proc.join()
    if integer.value != notasks:
        logging.error(
            "Unexpected value: %d (expected: %d)", integer.value, notasks)

if __name__ == "__main__":
    do_test(100)


Sample invocations and results:

Note that on a single CPU machine the error is not reported for every
execution but only for about every third run.
$ python --version
Python 2.6.5
$ uname -a
Linux ubuntu-desktop 2.6.32.11+drm33.2 #2 Fri Jun 18 20:30:49 CEST 2010 i686 GNU/Linux
$ python test_multiprocessing.py
ERROR:root:Unexpected value: 99 (expected: 100)

On a quadcore, the error occurs almost every time.
$ uname -a
Linux PC 2.6.35.13 #4 SMP Tue Dec 20 15:22:02 CET 2011 x86_64 GNU/Linux
$ ~/local/Python-2.7.3/python test_multiprocessing.py
ERROR:root:Unexpected value: 95 (expected: 100)
$ ~/local/Python-3.3.0/python test_multiprocessing.py
ERROR:root:Unexpected value: 86 (expected: 100)
History
Date User Action Args
2013-01-19 19:13:57lechtensetrecipients: + lechten
2013-01-19 19:13:57lechtensetmessageid: <1358622837.13.0.603431337609.issue16998@psf.upfronthosting.co.za>
2013-01-19 19:13:56lechtenlinkissue16998 messages
2013-01-19 19:13:53lechtencreate