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