Skip to content

Commit 4f10b8e

Browse files
[3.12] gh-125679: multiprocessing Lock and RLock - fix invalid representation string on MacOSX. (GH-125680) (#126534)
gh-125679: multiprocessing Lock and RLock - fix invalid representation string on MacOSX. (GH-125680) (cherry picked from commit 75f7cf9) Co-authored-by: Duprat <[email protected]>
1 parent d71da0f commit 4f10b8e

File tree

3 files changed

+126
-2
lines changed

3 files changed

+126
-2
lines changed

Lib/multiprocessing/synchronize.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ def __repr__(self):
174174
name = process.current_process().name
175175
if threading.current_thread().name != 'MainThread':
176176
name += '|' + threading.current_thread().name
177-
elif self._semlock._get_value() == 1:
177+
elif not self._semlock._is_zero():
178178
name = 'None'
179179
elif self._semlock._count() > 0:
180180
name = 'SomeOtherThread'
@@ -200,7 +200,7 @@ def __repr__(self):
200200
if threading.current_thread().name != 'MainThread':
201201
name += '|' + threading.current_thread().name
202202
count = self._semlock._count()
203-
elif self._semlock._get_value() == 1:
203+
elif not self._semlock._is_zero():
204204
name, count = 'None', 0
205205
elif self._semlock._count() > 0:
206206
name, count = 'SomeOtherThread', 'nonzero'

Lib/test/_test_multiprocessing.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,13 +1363,135 @@ def test_closed_queue_put_get_exceptions(self):
13631363

13641364
class _TestLock(BaseTestCase):
13651365

1366+
@staticmethod
1367+
def _acquire(lock, l=None):
1368+
lock.acquire()
1369+
if l is not None:
1370+
l.append(repr(lock))
1371+
1372+
@staticmethod
1373+
def _acquire_event(lock, event):
1374+
lock.acquire()
1375+
event.set()
1376+
time.sleep(1.0)
1377+
1378+
def test_repr_lock(self):
1379+
if self.TYPE != 'processes':
1380+
self.skipTest('test not appropriate for {}'.format(self.TYPE))
1381+
1382+
lock = self.Lock()
1383+
self.assertEqual(f'<Lock(owner=None)>', repr(lock))
1384+
1385+
lock.acquire()
1386+
self.assertEqual(f'<Lock(owner=MainProcess)>', repr(lock))
1387+
lock.release()
1388+
1389+
tname = 'T1'
1390+
l = []
1391+
t = threading.Thread(target=self._acquire,
1392+
args=(lock, l),
1393+
name=tname)
1394+
t.start()
1395+
time.sleep(0.1)
1396+
self.assertEqual(f'<Lock(owner=MainProcess|{tname})>', l[0])
1397+
lock.release()
1398+
1399+
t = threading.Thread(target=self._acquire,
1400+
args=(lock,),
1401+
name=tname)
1402+
t.start()
1403+
time.sleep(0.1)
1404+
self.assertEqual('<Lock(owner=SomeOtherThread)>', repr(lock))
1405+
lock.release()
1406+
1407+
pname = 'P1'
1408+
l = multiprocessing.Manager().list()
1409+
p = self.Process(target=self._acquire,
1410+
args=(lock, l),
1411+
name=pname)
1412+
p.start()
1413+
p.join()
1414+
self.assertEqual(f'<Lock(owner={pname})>', l[0])
1415+
1416+
lock = self.Lock()
1417+
event = self.Event()
1418+
p = self.Process(target=self._acquire_event,
1419+
args=(lock, event),
1420+
name='P2')
1421+
p.start()
1422+
event.wait()
1423+
self.assertEqual(f'<Lock(owner=SomeOtherProcess)>', repr(lock))
1424+
p.terminate()
1425+
13661426
def test_lock(self):
13671427
lock = self.Lock()
13681428
self.assertEqual(lock.acquire(), True)
13691429
self.assertEqual(lock.acquire(False), False)
13701430
self.assertEqual(lock.release(), None)
13711431
self.assertRaises((ValueError, threading.ThreadError), lock.release)
13721432

1433+
@staticmethod
1434+
def _acquire_release(lock, timeout, l=None, n=1):
1435+
for _ in range(n):
1436+
lock.acquire()
1437+
if l is not None:
1438+
l.append(repr(lock))
1439+
time.sleep(timeout)
1440+
for _ in range(n):
1441+
lock.release()
1442+
1443+
def test_repr_rlock(self):
1444+
if self.TYPE != 'processes':
1445+
self.skipTest('test not appropriate for {}'.format(self.TYPE))
1446+
1447+
lock = self.RLock()
1448+
self.assertEqual('<RLock(None, 0)>', repr(lock))
1449+
1450+
n = 3
1451+
for _ in range(n):
1452+
lock.acquire()
1453+
self.assertEqual(f'<RLock(MainProcess, {n})>', repr(lock))
1454+
for _ in range(n):
1455+
lock.release()
1456+
1457+
t, l = [], []
1458+
for i in range(n):
1459+
t.append(threading.Thread(target=self._acquire_release,
1460+
args=(lock, 0.1, l, i+1),
1461+
name=f'T{i+1}'))
1462+
t[-1].start()
1463+
for t_ in t:
1464+
t_.join()
1465+
for i in range(n):
1466+
self.assertIn(f'<RLock(MainProcess|T{i+1}, {i+1})>', l)
1467+
1468+
1469+
t = threading.Thread(target=self._acquire_release,
1470+
args=(lock, 0.2),
1471+
name=f'T1')
1472+
t.start()
1473+
time.sleep(0.1)
1474+
self.assertEqual('<RLock(SomeOtherThread, nonzero)>', repr(lock))
1475+
time.sleep(0.2)
1476+
1477+
pname = 'P1'
1478+
l = multiprocessing.Manager().list()
1479+
p = self.Process(target=self._acquire_release,
1480+
args=(lock, 0.1, l),
1481+
name=pname)
1482+
p.start()
1483+
p.join()
1484+
self.assertEqual(f'<RLock({pname}, 1)>', l[0])
1485+
1486+
event = self.Event()
1487+
lock = self.RLock()
1488+
p = self.Process(target=self._acquire_event,
1489+
args=(lock, event))
1490+
p.start()
1491+
event.wait()
1492+
self.assertEqual('<RLock(SomeOtherProcess, nonzero)>', repr(lock))
1493+
p.join()
1494+
13731495
def test_rlock(self):
13741496
lock = self.RLock()
13751497
self.assertEqual(lock.acquire(), True)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The :class:`multiprocessing.Lock` and :class:`multiprocessing.RLock`
2+
``repr`` values no longer say "unknown" on macOS.

0 commit comments

Comments
 (0)