| 1 | # Generator implementation using threads
|
|---|
| 2 |
|
|---|
| 3 | import thread
|
|---|
| 4 |
|
|---|
| 5 | Killed = 'Generator.Killed'
|
|---|
| 6 |
|
|---|
| 7 | class Generator:
|
|---|
| 8 | # Constructor
|
|---|
| 9 | def __init__(self, func, args):
|
|---|
| 10 | self.getlock = thread.allocate_lock()
|
|---|
| 11 | self.putlock = thread.allocate_lock()
|
|---|
| 12 | self.getlock.acquire()
|
|---|
| 13 | self.putlock.acquire()
|
|---|
| 14 | self.func = func
|
|---|
| 15 | self.args = args
|
|---|
| 16 | self.done = 0
|
|---|
| 17 | self.killed = 0
|
|---|
| 18 | thread.start_new_thread(self._start, ())
|
|---|
| 19 | # Internal routine
|
|---|
| 20 | def _start(self):
|
|---|
| 21 | try:
|
|---|
| 22 | self.putlock.acquire()
|
|---|
| 23 | if not self.killed:
|
|---|
| 24 | try:
|
|---|
| 25 | apply(self.func, (self,) + self.args)
|
|---|
| 26 | except Killed:
|
|---|
| 27 | pass
|
|---|
| 28 | finally:
|
|---|
| 29 | if not self.killed:
|
|---|
| 30 | self.done = 1
|
|---|
| 31 | self.getlock.release()
|
|---|
| 32 | # Called by producer for each value; raise Killed if no more needed
|
|---|
| 33 | def put(self, value):
|
|---|
| 34 | if self.killed:
|
|---|
| 35 | raise TypeError, 'put() called on killed generator'
|
|---|
| 36 | self.value = value
|
|---|
| 37 | self.getlock.release() # Resume consumer thread
|
|---|
| 38 | self.putlock.acquire() # Wait for next get() call
|
|---|
| 39 | if self.killed:
|
|---|
| 40 | raise Killed
|
|---|
| 41 | # Called by producer to get next value; raise EOFError if no more
|
|---|
| 42 | def get(self):
|
|---|
| 43 | if self.killed:
|
|---|
| 44 | raise TypeError, 'get() called on killed generator'
|
|---|
| 45 | self.putlock.release() # Resume producer thread
|
|---|
| 46 | self.getlock.acquire() # Wait for value to appear
|
|---|
| 47 | if self.done:
|
|---|
| 48 | raise EOFError # Say there are no more values
|
|---|
| 49 | return self.value
|
|---|
| 50 | # Called by consumer if no more values wanted
|
|---|
| 51 | def kill(self):
|
|---|
| 52 | if self.killed:
|
|---|
| 53 | raise TypeError, 'kill() called on killed generator'
|
|---|
| 54 | self.killed = 1
|
|---|
| 55 | self.putlock.release()
|
|---|
| 56 | # Clone constructor
|
|---|
| 57 | def clone(self):
|
|---|
| 58 | return Generator(self.func, self.args)
|
|---|
| 59 |
|
|---|
| 60 | def pi(g):
|
|---|
| 61 | k, a, b, a1, b1 = 2L, 4L, 1L, 12L, 4L
|
|---|
| 62 | while 1:
|
|---|
| 63 | # Next approximation
|
|---|
| 64 | p, q, k = k*k, 2L*k+1L, k+1L
|
|---|
| 65 | a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1
|
|---|
| 66 | # Print common digits
|
|---|
| 67 | d, d1 = a/b, a1/b1
|
|---|
| 68 | while d == d1:
|
|---|
| 69 | g.put(int(d))
|
|---|
| 70 | a, a1 = 10L*(a%b), 10L*(a1%b1)
|
|---|
| 71 | d, d1 = a/b, a1/b1
|
|---|
| 72 |
|
|---|
| 73 | def test():
|
|---|
| 74 | g = Generator(pi, ())
|
|---|
| 75 | g.kill()
|
|---|
| 76 | g = Generator(pi, ())
|
|---|
| 77 | for i in range(10): print g.get(),
|
|---|
| 78 | print
|
|---|
| 79 | h = g.clone()
|
|---|
| 80 | g.kill()
|
|---|
| 81 | while 1:
|
|---|
| 82 | print h.get(),
|
|---|
| 83 |
|
|---|
| 84 | test()
|
|---|