title: How to create a joinable semaphore in python?
body: <p>In some use-cases i need to wait for all already created threads to finish and make some decisions based on their results and see whether we need to move further or not - without <code>ThreadPoolExecutor.shutdown()</code>.</p>
  
  <p>i implemented it like this:</p>
  
  <pre><code>from threading import BoundedSemaphore, Event
  
  
  class JoinSemaphore(BoundedSemaphore):
      def __init__(self, value=1):
          super().__init__(value)
          self._empty = Event()
  
      def join(self, timeout=None):
          if self._value &lt; self._initial_value:
              self._empty.wait(timeout)
  
      def release(self):
          with self._cond:
              if self._value &gt;= self._initial_value:
                  raise ValueError("Semaphore released too many times")
              elif self._value == self._initial_value - 1:
                  self._empty.set()
  
              self._value += 1
              self._cond.notify()
  
      def acquired(self):
          with self._cond:
              return self._initial_value - self._value
  
  </code></pre>
  
  <p>Here i compute <code>self._value &lt; self._initial_value</code> without any guard and it has risk.
  when i write the join() function like bellow to prevent unwanted changes while i'm computing <code>self._value &lt; self._initial_value</code> i will face a deadlock when the main-thread joins on the semaphore and at this point other thread and not acquire <code>release()</code> lock because main thread already accrued it, but main thread still waiting for other threads. so this implementation is not correct.</p>
  
  <pre><code>    def join(self, timeout=None):
          with self._cond:
              if self._value &lt; self._initial_value:
                  self._empty.wait(timeout)
  </code></pre>
  
  <p>In third implementation i cannot guarantee that when i want to <code>wait()</code> for <code>_empty</code> event, other threads wouldn't have possibly submit their results and release the lock.</p>
  
  <pre><code>    def join(self, timeout=None):
          with self._cond:
              if self._value == self._initial_value:
                  return
          self._empty.wait(timeout)
  </code></pre>
  
  <p>the Question is:</p>
  
  <p>How can i compute <code>self._value &lt; self._initial_value</code> correctly using lock and wait for <code>_empty</code> event and release the lock before waiting on it to avoid deadlock?</p>
  
  <p>Thanks a lot</p>