| # Generator implementation using threads | 
 |  | 
 | import thread | 
 |  | 
 | Killed = 'Generator.Killed' | 
 |  | 
 | class Generator: | 
 |     # Constructor | 
 |     def __init__(self, func, args): | 
 |         self.getlock = thread.allocate_lock() | 
 |         self.putlock = thread.allocate_lock() | 
 |         self.getlock.acquire() | 
 |         self.putlock.acquire() | 
 |         self.func = func | 
 |         self.args = args | 
 |         self.done = 0 | 
 |         self.killed = 0 | 
 |         thread.start_new_thread(self._start, ()) | 
 |     # Internal routine | 
 |     def _start(self): | 
 |         try: | 
 |             self.putlock.acquire() | 
 |             if not self.killed: | 
 |                 try: | 
 |                     self.func(self, *self.args) | 
 |                 except Killed: | 
 |                     pass | 
 |         finally: | 
 |             if not self.killed: | 
 |                 self.done = 1 | 
 |                 self.getlock.release() | 
 |     # Called by producer for each value; raise Killed if no more needed | 
 |     def put(self, value): | 
 |         if self.killed: | 
 |             raise TypeError('put() called on killed generator') | 
 |         self.value = value | 
 |         self.getlock.release()  # Resume consumer thread | 
 |         self.putlock.acquire()  # Wait for next get() call | 
 |         if self.killed: | 
 |             raise Killed | 
 |     # Called by producer to get next value; raise EOFError if no more | 
 |     def get(self): | 
 |         if self.killed: | 
 |             raise TypeError('get() called on killed generator') | 
 |         self.putlock.release()  # Resume producer thread | 
 |         self.getlock.acquire()  # Wait for value to appear | 
 |         if self.done: | 
 |             raise EOFError  # Say there are no more values | 
 |         return self.value | 
 |     # Called by consumer if no more values wanted | 
 |     def kill(self): | 
 |         if self.killed: | 
 |             raise TypeError('kill() called on killed generator') | 
 |         self.killed = 1 | 
 |         self.putlock.release() | 
 |     # Clone constructor | 
 |     def clone(self): | 
 |         return Generator(self.func, self.args) | 
 |  | 
 | def pi(g): | 
 |     k, a, b, a1, b1 = 2, 4, 1, 12, 4 | 
 |     while 1: | 
 |         # Next approximation | 
 |         p, q, k = k*k, 2*k+1, k+1 | 
 |         a, b, a1, b1 = a1, b1, p*a+q*a1, p*b+q*b1 | 
 |         # Print common digits | 
 |         d, d1 = a/b, a1/b1 | 
 |         while d == d1: | 
 |             g.put(int(d)) | 
 |             a, a1 = 10*(a%b), 10*(a1%b1) | 
 |             d, d1 = a/b, a1/b1 | 
 |  | 
 | def test(): | 
 |     g = Generator(pi, ()) | 
 |     g.kill() | 
 |     g = Generator(pi, ()) | 
 |     for i in range(10): print(g.get(), end=' ') | 
 |     print() | 
 |     h = g.clone() | 
 |     g.kill() | 
 |     while 1: | 
 |         print(h.get(), end=' ') | 
 |  | 
 | test() |