threading.semaphore

semaphore排他オブジェクトです。
threading.Semaphoreとthreading.BoundedSemaphoreがあります。

import time
import thread
import threading
import random

counter = 0

counter = 0

def semaphore_func(semaphore):
    with semaphore:
        thread_func()
    global counter
    counter -= 1  
    
def thread_func():
    global counter
    counter += 1
    print "counter: ", counter
    time.sleep(3)
    
def main():
    max_connection = 5
    semaphore = threading.Semaphore(max_connection) # default is 1
    
    end_count = 0
    while end_count < 15:
        time.sleep( random.random() * 0.5 + 0.2 )
        with semaphore:
            threading.Thread( target = semaphore_func, args = (semaphore,) ).start()
        end_count += 1

    print "wait for %d threads execution" % counter
    while not counter == 0:
        pass

if __name__ == '__main__':
    main()

threading.Semaphoreのコンストラクタで内部カウンタの初期化を行います。
デフォルト値は1です。
スレッド数の上限が決まっているときなどに使用します。
ここでいうmax_connection数以上thread_funcが行われることはありません。
acquireで内部カウンタをデクリメントし、releaseでインクリメントします。
このとき、内部カウンタ0のセマフォに対してacquireを行うと、内部カウンタが1以上になるまで待機します。
threadingはもうひとつBoundedSemaphoreを提供しています。

import threading

def main():

    max_connection = 5
    semaphore = threading.BoundedSemaphore(max_connection) # default 1
    try:
        semaphore.release()
    except ValueError:
        print "error"
        return

if __name__ == '__main__':
    main()

内部カウンタが初期値以上になると例外を発生します。
threading.Semaphoreにはこの機能はありません。