473,386 Members | 1,726 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

atomic operations in presence of multithreading

I am wondering which operations in Python
are guaranteed to be atomic in the presence
of multi-threading. In particular, are assignment
and reading of a dictionary entry atomic?
For example, initially:
dictionary = {}
dictionary[key] = old_value
Then thread 1 does:
v = dictionary[key]
And thread 2 does:
dictionary[key] = new_value2
And thread 3 does:
dictionary[key] = new_value3
What I want to make sure of is that
thread 1 will read either the old_value
for key, or new_value2, or new_value3,
but not an intermediate value.
Which value in particular does not matter to me, as that
obviously depends on timing. I just want to make sure
that the dictionary internal data structures can't
become corrupted by multiple writers / readers.
Note: I realize that in this particular case
I can use locks to guarantee safety, but I am
wondering whether the basic language operations
such as dictionary reads and updates are guaranteed
to be atomic.
A related, more general question, is which
Python operations are atomic, and which are not.
I was unable to find this in the language reference,
but please direct me to the correct location
if I missed it.
Thanks,
Glenn
Jul 18 '05 #1
8 3556
Glenn Kasten wrote:
I am wondering which operations in Python
are guaranteed to be atomic in the presence
of multi-threading. In particular, are assignment
and reading of a dictionary entry atomic? [snip] I just want to make sure
that the dictionary internal data structures can't
become corrupted by multiple writers / readers. [snip] Python operations are atomic, and which are not.
I was unable to find this in the language reference,
but please direct me to the correct location
if I missed it.


It's probably not spelled out anywhere, but the "global interpreter
lock" entry and the Glossary and the first few paragraphs of section 8.1
of the documentation ("Thread State and the Global Interpreter Lock")
give you the gist of it.

Basically: multiple threads can't corrupt the interpreter's internals
(but a buggy C extension could).

-Dave
Jul 18 '05 #2
Dave Brueck wrote:
Glenn Kasten wrote:
I am wondering which operations in Python
are guaranteed to be atomic in the presence
of multi-threading. In particular, are assignment
and reading of a dictionary entry atomic?


[...]
Basically: multiple threads can't corrupt the interpreter's internals
(but a buggy C extension could).


The "dis" module can be helpful in analyzing such things, sometimes.
Realizing that the GIL ensures that individual bytecodes are
executed atomically ("boom!"), anything that shows up as a
separate bytecode instruction is basically thread-safe:
def func(): .... v = dictionary[key]
.... def func2(): .... dictionary[key] = new_value2
.... dis.dis(func) 2 0 LOAD_GLOBAL 0 (dictionary)
3 LOAD_GLOBAL 1 (key)
6 BINARY_SUBSCR
7 STORE_FAST 0 (v)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE dis.dis(func2)

2 0 LOAD_GLOBAL 0 (new_value2)
3 LOAD_GLOBAL 1 (dictionary)
6 LOAD_GLOBAL 2 (key)
9 STORE_SUBSCR
10 LOAD_CONST 0 (None)
13 RETURN_VALUE

The key instructions in the above are the dictionary lookup,
which is merely "BINARY_SUBSCR" in func(), and the dictionary
assignment, which is "STORE_SUBSCR" in func2(). If func
and func2 were in separate threads, either the lookup or
the store executes first, then the other, but they cannot
both be executing at the same time.

-Peter
Jul 18 '05 #3
Peter Hansen <pe***@engcorp.com> writes:
Dave Brueck wrote:
Glenn Kasten wrote:
I am wondering which operations in Python
are guaranteed to be atomic in the presence
of multi-threading. In particular, are assignment
and reading of a dictionary entry atomic?
> [...]
Basically: multiple threads can't corrupt the interpreter's
internals (but a buggy C extension could).


[...]
The key instructions in the above are the dictionary lookup,
which is merely "BINARY_SUBSCR" in func(), and the dictionary
assignment, which is "STORE_SUBSCR" in func2(). If func
and func2 were in separate threads, either the lookup or
the store executes first, then the other, but they cannot
both be executing at the same time.


As was pointed out to me when this came up recently, it is possible
for callbacks into python to screw this simple picture up a little.

The obvious case is a user-defined class with a __setitem__ method. In
this case, STORE_SUBSCR calls arbitrary Python code, and so can be
interrupted by a thread switch.

Given that the original question was about dictionaries, which are
coded in C (and so not subject to this issue) there is still the
following case: when the old value stored in the dictionary is
replaced, that could be the last reference to it. When the old value
is freed, its __del__ method gets called - arbitrary Python code
again.

But the basic idea is sound. The interpreter releases the GIL *only*
between Python bytecodes. As long as you cater for recursive cases
like the above (and obvious ones like CALL_METHOD), you're OK.

Finally, C code has the option of explicitly releasing the GIL -
"long-running" operations like file reads do this, but basic ops
don't.

Paul.
--
This signature intentionally left blank
Jul 18 '05 #4
Paul Moore wrote:
Peter Hansen <pe***@engcorp.com> writes:

Dave Brueck wrote:

Glenn Kasten wrote:
I am wondering which operations in Python
are guaranteed to be atomic in the presence
of multi-threading. In particular, are assignment
and reading of a dictionary entry atomic?

> [...]

Basically: multiple threads can't corrupt the interpreter's
internals (but a buggy C extension could).


[...]

The key instructions in the above are the dictionary lookup,
which is merely "BINARY_SUBSCR" in func(), and the dictionary
assignment, which is "STORE_SUBSCR" in func2(). If func
and func2 were in separate threads, either the lookup or
the store executes first, then the other, but they cannot
both be executing at the same time.

As was pointed out to me when this came up recently, it is possible
for callbacks into python to screw this simple picture up a little.

The obvious case is a user-defined class with a __setitem__ method. In
this case, STORE_SUBSCR calls arbitrary Python code, and so can be
interrupted by a thread switch.

Given that the original question was about dictionaries, which are
coded in C (and so not subject to this issue) there is still the
following case: when the old value stored in the dictionary is
replaced, that could be the last reference to it. When the old value
is freed, its __del__ method gets called - arbitrary Python code
again.

But the basic idea is sound. The interpreter releases the GIL *only*
between Python bytecodes. As long as you cater for recursive cases
like the above (and obvious ones like CALL_METHOD), you're OK.


Yep, though I think the OP was mostly concerned with Python's internals
gettin messed up by unlocked multithreaded access, so he doesn't have to
be concerned about the above.

-Dave
Jul 18 '05 #5
Paul Moore <pf******@yahoo.co.uk> wrote in news:y8**********@yahoo.co.uk:
Given that the original question was about dictionaries, which are
coded in C (and so not subject to this issue) there is still the
following case: when the old value stored in the dictionary is
replaced, that could be the last reference to it. When the old value
is freed, its __del__ method gets called - arbitrary Python code
again.


Right, but the new value has already been stored in the dictionary at the
point where the __del__ method is called, so as far as the OP is concerned
this is still safe.
Jul 18 '05 #6
Duncan Booth wrote:
Paul Moore <pf******@yahoo.co.uk> wrote in news:y8**********@yahoo.co.uk:
Given that the original question was about dictionaries, which are
coded in C (and so not subject to this issue) there is still the
following case: when the old value stored in the dictionary is
replaced, that could be the last reference to it. When the old value
is freed, its __del__ method gets called - arbitrary Python code
again.


Right, but the new value has already been stored in the dictionary at the
point where the __del__ method is called, so as far as the OP is concerned
this is still safe.


For some definition of "safe", perhaps. It won't corrupt any Python
internals, but if the __del__() method has side effects that the
threaded code is relying on, it may give unexpected results. (One might
want to rely on the fact that, once an object holding a socket is
removed from a dictionary, that socket will be closed; if that close
happens in the object's __del__(), then there's no guarantee that it
*will* actually be closed before a thread switch occurs. (Relying on
__del__() is hazardous in any case, actually, thanks to differing GC
between different implementations of Python, but it's even worse in a
threaded environment.))

Jeff Shannon
Technician/Programmer
Credit International

Jul 18 '05 #7
Dave Brueck <da**@pythonapocrypha.com> writes:
Yep, though I think the OP was mostly concerned with Python's
internals gettin messed up by unlocked multithreaded access, so he
doesn't have to be concerned about the above.


I don't think that Python's internals can *ever* be messed up by
unlocked multithreaded access - that's what the GIL is for.

Paul.
--
This signature intentionally left blank
Jul 18 '05 #8
Paul Moore wrote:
Dave Brueck <da**@pythonapocrypha.com> writes:

Yep, though I think the OP was mostly concerned with Python's
internals gettin messed up by unlocked multithreaded access, so he
doesn't have to be concerned about the above.

I don't think that Python's internals can *ever* be messed up by
unlocked multithreaded access - that's what the GIL is for.


Yeah, that was mentioned earlier:

"multiple threads can't corrupt the interpreter's internals (but a buggy
C extension could)."

-Dave
Jul 18 '05 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: Paul Moore | last post by:
I can't find anything which spells this out in the manuals. I guess that, at some level, the answer is "a single bytecode operation", but I'm not sure that explains it for me. This thought was...
42
by: Shayan | last post by:
Is there a boolean flag that can be set atomically without needing to wrap it in a mutex? This flag will be checked constantly by multiple threads so I don't really want to deal with the overhead...
7
by: dm | last post by:
Hi, I'd like to know if the C standard can guarantee that an assignment to/from a variable will be atomic, that is will occur in a single indivisible instruction. For example, if I have the...
28
by: robert | last post by:
In very rare cases a program crashes (hard to reproduce) : * several threads work on an object tree with dict's etc. in it. Items are added, deleted, iteration over .keys() ... ). The threads are...
6
by: blackstreetcat | last post by:
consider this code : int i; //gobal var Thread1: i=some value; Thread2: if (i==2) dosomething(); else dosomethingelse();
9
by: Dave Stallard | last post by:
Pardon if this is the wrong newsgroup for this question, and/or if this question is naive. I have a multi-threaded Windows application in which certain variables/object fields are shared: one...
11
by: japhy | last post by:
Is there a way to read a line (a series of characters ending in a newline) from a file (either by descriptor or stream) atomically, without buffering additional contents of the file?
2
by: Freedom fighter | last post by:
Hello, Is a singleton class the same as an atomic class? I know that a singleton class can only be instantiated once, but does that concept apply to an atomic class? Thank you.
11
by: Jon Harrop | last post by:
Can read locks on a data structure be removed safely when updates are limited to replacing a reference? In other words, is setting a reference an atomic operation? I have been assuming that all...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.