mirror of
https://github.com/python/cpython.git
synced 2026-01-06 15:32:22 +00:00
gh-112075: Remove critical section in dict.get (gh-129336)
The `dict.get` implementation uses `_Py_dict_lookup_threadsafe`, which is thread-safe, so we remove the critical section from the argument clinic. Add a test for concurrent dict get and set operations.
This commit is contained in:
parent
a4459c34ea
commit
64c417dee5
3 changed files with 24 additions and 6 deletions
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
from ast import Or
|
||||
from functools import partial
|
||||
from threading import Thread
|
||||
from threading import Barrier, Thread
|
||||
from unittest import TestCase
|
||||
|
||||
try:
|
||||
|
|
@ -142,6 +142,27 @@ def writer_func(l):
|
|||
for ref in thread_list:
|
||||
self.assertIsNone(ref())
|
||||
|
||||
def test_racing_get_set_dict(self):
|
||||
"""Races getting and setting a dict should be thread safe"""
|
||||
THREAD_COUNT = 10
|
||||
barrier = Barrier(THREAD_COUNT)
|
||||
def work(d):
|
||||
barrier.wait()
|
||||
for _ in range(1000):
|
||||
d[10] = 0
|
||||
d.get(10, None)
|
||||
_ = d[10]
|
||||
|
||||
d = {}
|
||||
worker_threads = []
|
||||
for ii in range(THREAD_COUNT):
|
||||
worker_threads.append(Thread(target=work, args=[d]))
|
||||
for t in worker_threads:
|
||||
t.start()
|
||||
for t in worker_threads:
|
||||
t.join()
|
||||
|
||||
|
||||
def test_racing_set_object_dict(self):
|
||||
"""Races assigning to __dict__ should be thread safe"""
|
||||
class C: pass
|
||||
|
|
|
|||
4
Objects/clinic/dictobject.c.h
generated
4
Objects/clinic/dictobject.c.h
generated
|
|
@ -94,9 +94,7 @@ dict_get(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
|
|||
}
|
||||
default_value = args[1];
|
||||
skip_optional:
|
||||
Py_BEGIN_CRITICAL_SECTION(self);
|
||||
return_value = dict_get_impl((PyDictObject *)self, key, default_value);
|
||||
Py_END_CRITICAL_SECTION();
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
|
|
@ -312,4 +310,4 @@ dict_values(PyObject *self, PyObject *Py_UNUSED(ignored))
|
|||
{
|
||||
return dict_values_impl((PyDictObject *)self);
|
||||
}
|
||||
/*[clinic end generated code: output=4956c5b276ea652f input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=0f04bf0e7e6b130f input=a9049054013a1b77]*/
|
||||
|
|
|
|||
|
|
@ -4248,7 +4248,6 @@ dict___contains__(PyDictObject *self, PyObject *key)
|
|||
}
|
||||
|
||||
/*[clinic input]
|
||||
@critical_section
|
||||
dict.get
|
||||
|
||||
key: object
|
||||
|
|
@ -4260,7 +4259,7 @@ Return the value for key if key is in the dictionary, else default.
|
|||
|
||||
static PyObject *
|
||||
dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
|
||||
/*[clinic end generated code: output=bba707729dee05bf input=a631d3f18f584c60]*/
|
||||
/*[clinic end generated code: output=bba707729dee05bf input=279ddb5790b6b107]*/
|
||||
{
|
||||
PyObject *val = NULL;
|
||||
Py_hash_t hash;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue