def FairSelect(*guards): """ It sorts the list of guards in order based on the history for the chosen guards in this FairSelect located at a specific line in a specific process. Internally it invokes a priority select on the new order of guards. Timer and Skip guards are placed with lowest priority, since it does make sence to make them fair. """ alt_key = str(current_process_id()) + '_' + str(inspect.currentframe().f_back.f_lineno) A = AltHistory() H = A.get_history(alt_key) L = [] L_last = [] for item in guards: try: chan_name = item.g[0].channel.name if H.has_key(chan_name): L.append((H[chan_name], item.g)) else: L.append((0, item.g)) except AttributeError: try: L_last.append(item.g) except AttributeError: raise Exception('Can not use ' + str(item) + ' as guard. Only use *Guard types for AltSelect') L.sort() L = [x[1] for x in L] + L_last if pycsp.current.trace: import pycsp.common.trace as trace a = trace.Alternation(L) a.set_execute_frame(-3) else: a = Alternation(L) a.set_execute_frame(-2) result = a.execute() try: chan_name = result[0].channel.name A.update_history(alt_key, chan_name) except: # Can not record skip og timer guard. pass return result
def AltSelect(*guards): """ AltSelect is a wrapper to Alternation with a much more intuitive interface. It performs a prioritized choice from a list of guard objects and returns a tuple with the selected channel end and the read msg if there is one, otherwise None. >>> from __init__ import * >>> C = Channel() >>> cin = C.reader() >>> ch_end, msg = AltSelect(InputGuard(cin), SkipGuard()) >>> if ch_end == cin: ... print msg ... else: ... print msg == None True AltSelect supports skip, timeout, input and output guards. >>> @choice ... def callback(type, channel_input = None): ... print type, channel_input >>> A, B = Channel('A'), Channel('B') >>> cin, cout = A.reader(), B.writer() >>> g1 = InputGuard(cin, action=callback('input')) >>> g2 = OutputGuard(cout, msg=[range(10),range(100)], action=callback('output')) >>> g3 = TimeoutGuard(seconds=0.1, action=callback('timeout')) >>> _ = AltSelect(g1, g2, g3) timeout None Note that AltSelect always performs the guard that was chosen, i.e. channel input or output is executed within the AltSelect so even the empty choice with an AltSelect or where the results are simply ignored, still performs the guarded input or output. >>> L = [] >>> @choice ... def action(channel_input): ... L.append(channel_input) >>> @process ... def P1(cout, n=5): ... for i in range(n): ... cout(i) >>> @process ... def P2(cin1, cin2, n=10): ... for i in range(n): ... _ = AltSelect( InputGuard(cin1, action=action()), InputGuard(cin2, action=action()) ) >>> C1, C2 = Channel(), Channel() >>> Parallel(P1(C1.writer()), P1(C2.writer()), P2(C1.reader(), C2.reader())) >>> len(L) 10 >>> L.sort() >>> L [0, 0, 1, 1, 2, 2, 3, 3, 4, 4] """ L = [] # Build guard list for item in guards: try: L.append(item.g) except AttributeError: raise Exception('Cannot use ' + str(item) + ' as guard. Only use *Guard types for AltSelect') if pycsp.current.trace: import pycsp.common.trace as trace a = trace.Alternation(L) a.set_execute_frame(-3) else: a = Alternation(L) a.set_execute_frame(-2) return a.execute()