# Collection of code snippets by Arne Vajhøj 
# (from articles on eksperten.dk / vajhoej.dk written sometime between 2004 and now) 
import threading
import time

class Data(object):
    def __init__(self, _s):
        self.s = _s

lck = threading.RLock()

class Processor(threading.Thread):
    def __init__(self, _d):
        super(Processor, self).__init__()
        self.d = _d
    def run(self):
        # simulate some work between get and set
        lck.acquire(1)
        s = self.d.s
        time.sleep(0.001)
        self.d.s = s + "X"
        lck.release()

def test(njobs, nthreads):
    # setup data
    d = Data("")
    # process
    for i in range(njobs / nthreads): # // in Python 3.x
        # create threads
        t = []
        for j in range(nthreads):
            t.append(Processor(d))
        # start threads
        for j in range(nthreads):
            t[j].start()
        # wait for threads to complete
        for j in range(nthreads):
            t[j].join()
    print("%d threads : expected = %d, actual = %d" % (nthreads, njobs, len(d.s)))

test(2560, 1)
test(2560, 2)
test(2560, 4)
test(2560, 8)
test(2560, 16)
test(2560, 32)
test(2560, 64)
