Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Lib/multiprocessing/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1051,20 +1051,22 @@ def close(self, *args):


class AcquirerProxy(BaseProxy):
_exposed_ = ('acquire', 'release')
_exposed_ = ('acquire', 'release', 'locked')
def acquire(self, blocking=True, timeout=None):
args = (blocking,) if timeout is None else (blocking, timeout)
return self._callmethod('acquire', args)
def release(self):
return self._callmethod('release')
def locked(self):
return self._callmethod('locked')
def __enter__(self):
return self._callmethod('acquire')
def __exit__(self, exc_type, exc_val, exc_tb):
return self._callmethod('release')


class ConditionProxy(AcquirerProxy):
_exposed_ = ('acquire', 'release', 'wait', 'notify', 'notify_all')
_exposed_ = ('acquire', 'release', 'locked', 'wait', 'notify', 'notify_all')
def wait(self, timeout=None):
return self._callmethod('wait', (timeout,))
def notify(self, n=1):
Expand Down
3 changes: 3 additions & 0 deletions Lib/multiprocessing/synchronize.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ def _make_methods(self):
self.acquire = self._semlock.acquire
self.release = self._semlock.release

def locked(self):
return self._semlock._count() != 0

def __enter__(self):
return self._semlock.__enter__()

Expand Down
13 changes: 11 additions & 2 deletions Lib/test/_test_multiprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1348,23 +1348,32 @@ class _TestLock(BaseTestCase):
def test_lock(self):
lock = self.Lock()
self.assertEqual(lock.acquire(), True)
self.assertEqual(lock.locked(), True)
self.assertEqual(lock.acquire(False), False)
self.assertEqual(lock.release(), None)
self.assertFalse(lock.locked())
self.assertRaises((ValueError, threading.ThreadError), lock.release)

def test_rlock(self):
lock = self.RLock()
self.assertEqual(lock.acquire(), True)
self.assertTrue(lock.locked())
self.assertEqual(lock.acquire(), True)
self.assertEqual(lock.acquire(), True)
self.assertEqual(lock.release(), None)
self.assertTrue(lock.locked())
self.assertEqual(lock.release(), None)
self.assertEqual(lock.release(), None)
self.assertFalse(lock.locked())
self.assertRaises((AssertionError, RuntimeError), lock.release)

def test_lock_context(self):
with self.Lock():
pass
with self.Lock() as locked:
self.assertTrue(locked)

def test_rlock_context(self):
with self.RLock() as locked:
self.assertTrue(locked)


class _TestSemaphore(BaseTestCase):
Expand Down
13 changes: 13 additions & 0 deletions Modules/_threadmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,17 @@ Do note that if the lock was acquire()d several times in a row by the\n\
current thread, release() needs to be called as many times for the lock\n\
to be available for other threads.");

static PyObject *
rlock_locked(rlockobject *self, PyObject *Py_UNUSED(ignored))
{
return PyBool_FromLong(self->rlock_count);
}

PyDoc_STRVAR(rlock_locked_doc,
"locked()\n\
\n\
Returns whether this lock is locked right now or not.");

static PyObject *
rlock_acquire_restore(rlockobject *self, PyObject *args)
{
Expand Down Expand Up @@ -719,6 +730,8 @@ static PyMethodDef rlock_methods[] = {
METH_VARARGS | METH_KEYWORDS, rlock_acquire_doc},
{"release", (PyCFunction)rlock_release,
METH_NOARGS, rlock_release_doc},
{"locked", (PyCFunction)rlock_locked,
METH_NOARGS, rlock_locked_doc},
{"_is_owned", (PyCFunction)rlock_is_owned,
METH_NOARGS, rlock_is_owned_doc},
{"_acquire_restore", (PyCFunction)rlock_acquire_restore,
Expand Down