⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 runq.scm

📁 MSYS在windows下模拟了一个类unix的终端
💻 SCM
字号:
;;;; runq.scm --- the runq data structure;;;;;;;; 	Copyright (C) 1996, 2001 Free Software Foundation, Inc.;;;;;;;; This program is free software; you can redistribute it and/or modify;;;; it under the terms of the GNU General Public License as published by;;;; the Free Software Foundation; either version 2, or (at your option);;;; any later version.;;;;;;;; This program is distributed in the hope that it will be useful,;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the;;;; GNU General Public License for more details.;;;;;;;; You should have received a copy of the GNU General Public License;;;; along with this software; see the file COPYING.  If not, write to;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,;;;; Boston, MA 02111-1307 USA;;;;;;;; As a special exception, the Free Software Foundation gives permission;;;; for additional uses of the text contained in its release of GUILE.;;;;;;;; The exception is that, if you link the GUILE library with other files;;;; to produce an executable, this does not by itself cause the;;;; resulting executable to be covered by the GNU General Public License.;;;; Your use of that executable is in no way restricted on account of;;;; linking the GUILE library code into it.;;;;;;;; This exception does not however invalidate any other reasons why;;;; the executable file might be covered by the GNU General Public License.;;;;;;;; This exception applies only to the code released by the;;;; Free Software Foundation under the name GUILE.  If you copy;;;; code from other Free Software Foundation releases into a copy of;;;; GUILE, as the General Public License permits, the exception does;;;; not apply to the code that you add in this way.  To avoid misleading;;;; anyone as to the status of such modified files, you must delete;;;; this exception notice from them.;;;;;;;; If you write modifications of your own for GUILE, it is your choice;;;; whether to permit this exception to apply to your modifications.;;;; If you do not wish that, delete this exception notice.;;;;;;; Commentary:;;; One way to schedule parallel computations in a serial environment is;;; to explicitly divide each task up into small, finite execution time,;;; strips.  Then you interleave the execution of strips from various;;; tasks to achieve a kind of parallelism.  Runqs are a handy data;;; structure for this style of programming.;;;;;; We use thunks (nullary procedures) and lists of thunks to represent;;; strips.  By convention, the return value of a strip-thunk must either;;; be another strip or the value #f.;;;;;; A runq is a procedure that manages a queue of strips.  Called with no;;; arguments, it processes one strip from the queue.  Called with;;; arguments, the arguments form a control message for the queue.  The;;; first argument is a symbol which is the message selector.;;;;;; A strip is processed this way: If the strip is a thunk, the thunk is;;; called -- if it returns a strip, that strip is added back to the;;; queue.  To process a strip which is a list of thunks, the CAR of that;;; list is called.  After a call to that CAR, there are 0, 1, or 2 strips;;; -- perhaps one returned by the thunk, and perhaps the CDR of the;;; original strip if that CDR is not nil.  The runq puts whichever of;;; these strips exist back on the queue.  (The exact order in which;;; strips are put back on the queue determines the scheduling behavior of;;; a particular queue -- it's a parameter.);;; Code:(define-module (ice-9 runq)  :use-module (ice-9 q)  :export (runq-control make-void-runq make-fair-runq	   make-exclusive-runq make-subordinate-runq-to strip-sequence	   fair-strip-subtask));;;;;;; 	(runq-control q msg . args);;;;;; 		processes in the default way the control messages that;;; 		can be sent to a runq.  Q should be an ordinary;;; 		Q (see utils/q.scm).;;;;;; 		The standard runq messages are:;;;;;; 		'add! strip0 strip1...		;; to enqueue one or more strips;;; 		'enqueue! strip0 strip1...	;; to enqueue one or more strips;;; 		'push! strip0 ...		;; add strips to the front of the queue;;; 		'empty?				;; true if it is;;; 		'length				;; how many strips in the queue?;;; 		'kill!				;; empty the queue;;; 		else				;; throw 'not-understood;;;(define (runq-control q msg . args)  (case msg    ((add!)			(for-each (lambda (t) (enq! q t)) args) '*unspecified*)    ((enqueue!)			(for-each (lambda (t) (enq! q t)) args) '*unspecified*)    ((push!)			(for-each (lambda (t) (q-push! q t)) args) '*unspecified*)    ((empty?)			(q-empty? q))    ((length)			(q-length q))    ((kill!)			(set! q (make-q)))    (else			(throw 'not-understood msg args))))(define (run-strip thunk) (catch #t thunk (lambda ign (warn 'runq-strip thunk ign) #f)));;;;;;; make-void-runq;;;;;; Make a runq that discards all messages except "length", for which;;; it returns 0.;;;(define (make-void-runq)  (lambda opts    (and opts	(apply-to-args opts	  (lambda (msg . args)	    (case msg	      ((length)		0)	      (else		#f)))))));;;;;;; 	(make-fair-runq);;;;;; 		Returns a runq procedure.;;; 		Called with no arguments, the procedure processes one strip from the queue.;;; 		Called with arguments, it uses runq-control.;;;;;; 		In a fair runq, if a strip returns a new strip X, X is added;;; 		to the end of the queue, meaning it will be the last to execute;;; 		of all the remaining procedures.;;;(define (make-fair-runq)  (letrec ((q (make-q))	   (self	    (lambda ctl	      (if ctl		  (apply runq-control q ctl)		  (and (not (q-empty? q))		       (let ((next-strip (deq! q)))			 (cond			  ((procedure? next-strip)	(let ((k (run-strip next-strip)))							  (and k (enq! q k))))			  ((pair? next-strip) (let ((k (run-strip (car next-strip))))						(and k (enq! q k)))					      (if (not (null? (cdr next-strip)))						  (enq! q (cdr next-strip)))))			 self))))))    self));;;;;;; 	(make-exclusive-runq);;;;;; 		Returns a runq procedure.;;; 		Called with no arguments, the procedure processes one strip from the queue.;;; 		Called with arguments, it uses runq-control.;;;;;; 		In an exclusive runq, if a strip W returns a new strip X, X is added;;; 		to the front of the queue, meaning it will be the next to execute;;; 		of all the remaining procedures.;;;;;; 		An exception to this occurs if W was the CAR of a list of strips.;;; 		In that case, after the return value of W is pushed onto the front;;; 	 	of the queue, the CDR of the list of strips is pushed in front;;; 		of that (if the CDR is not nil).   This way, the rest of the thunks;;; 		in the list that contained W have priority over the return value of W.;;;(define (make-exclusive-runq)  (letrec ((q (make-q))	   (self	    (lambda ctl	      (if ctl		  (apply runq-control q ctl)		  (and (not (q-empty? q))		       (let ((next-strip (deq! q)))			 (cond			  ((procedure? next-strip)	(let ((k (run-strip next-strip)))							  (and k (q-push! q k))))			  ((pair? next-strip) (let ((k (run-strip (car next-strip))))						(and k (q-push! q k)))					      (if (not (null? (cdr next-strip)))						  (q-push! q (cdr next-strip)))))			 self))))))    self));;;;;;; 	(make-subordinate-runq-to superior basic-inferior);;;;;; 		Returns a runq proxy for the runq basic-inferior.;;;;;; 		The proxy watches for operations on the basic-inferior that cause;;; 		a transition from a queue length of 0 to a non-zero length and;;; 		vice versa.   While the basic-inferior queue is not empty,;;; 		the proxy installs a task on the superior runq.  Each strip;;; 		of that task processes N strips from the basic-inferior where;;; 		N is the length of the basic-inferior queue when the proxy;;; 		strip is entered.  [Countless scheduling variations are possible.];;;(define (make-subordinate-runq-to superior-runq basic-runq)  (let ((runq-task (cons #f #f)))    (set-car! runq-task	      (lambda ()		(if (basic-runq 'empty?)		    (set-cdr! runq-task #f)		    (do ((n (basic-runq 'length) (1- n)))			((<= n 0)		 #f)		      (basic-runq)))))    (letrec ((self	      (lambda ctl		(if (not ctl)		    (let ((answer (basic-runq)))		      (self 'empty?)		      answer)		    (begin		      (case (car ctl)			((suspend)		(set-cdr! runq-task #f))			(else		      	(let ((answer (apply basic-runq ctl)))						  (if (and (not (cdr runq-task)) (not (basic-runq 'empty?)))						      (begin							(set-cdr! runq-task runq-task)							(superior-runq 'add! runq-task)))						  answer))))))))      self)));;;;;;;	(define fork-strips (lambda args args));;;		Return a strip that starts several strips in;;;		parallel.   If this strip is enqueued on a fair;;;		runq, strips of the parallel subtasks will run;;;		round-robin style.;;;(define fork-strips (lambda args args));;;;;;; 	(strip-sequence . strips);;;;;; 		Returns a new strip which is the concatenation of the argument strips.;;;(define ((strip-sequence . strips))  (let loop ((st (let ((a strips)) (set! strips #f) a)))    (and (not (null? st))	 (let ((then ((car st))))	   (if then	       (lambda () (loop (cons then (cdr st))))	       (lambda () (loop (cdr st))))))));;;;;;; 	(fair-strip-subtask . initial-strips);;;;;; 		Returns a new strip which is the synchronos, fair,;;; 		parallel execution of the argument strips.;;;;;;;;;(define (fair-strip-subtask . initial-strips)  (let ((st (make-fair-runq)))    (apply st 'add! initial-strips)    st));;; runq.scm ends here

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -