Issue #11714: Use 'with' statements to assure a Semaphore releases a
condition variable.  Original patch by Thomas Rachel.
diff --git a/Lib/threading.py b/Lib/threading.py
index e7f7df7..3526894 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -253,31 +253,29 @@
             raise ValueError("can't specify timeout for non-blocking acquire")
         rc = False
         endtime = None
-        self._cond.acquire()
-        while self._value == 0:
-            if not blocking:
-                break
-            if timeout is not None:
-                if endtime is None:
-                    endtime = _time() + timeout
-                else:
-                    timeout = endtime - _time()
-                    if timeout <= 0:
-                        break
-            self._cond.wait(timeout)
-        else:
-            self._value -= 1
-            rc = True
-        self._cond.release()
+        with self._cond:
+            while self._value == 0:
+                if not blocking:
+                    break
+                if timeout is not None:
+                    if endtime is None:
+                        endtime = _time() + timeout
+                    else:
+                        timeout = endtime - _time()
+                        if timeout <= 0:
+                            break
+                self._cond.wait(timeout)
+            else:
+                self._value -= 1
+                rc = True
         return rc
 
     __enter__ = acquire
 
     def release(self):
-        self._cond.acquire()
-        self._value += 1
-        self._cond.notify()
-        self._cond.release()
+        with self._cond:
+            self._value += 1
+            self._cond.notify()
 
     def __exit__(self, t, v, tb):
         self.release()