这段代码实际上是在推动我理解的极限,所以请原谅我。
以前,我在Racket中实现了以下代码中的协同:
;; Coroutine definition
(define (make-generator procedure)
(define last-return values)
(define last-value #f)
(define status 'suspended)
(define (last-continuation _)
(let ([result (procedure yield)])
(last-return result)))
(define (yield value)
(call/cc (lambda (continuation)
(set! last-continuation continuation)
(set! last-value value)
(set! status 'suspended)
(last-return value))))
(lambda args
(call/cc (lambda (return)
(set! last-return return)
(cond ((null? args)
(let ()
(set! status 'dead)
(last-continuation last-value)))
((eq? (car args) 'coroutine?) 'coroutine)
((eq? (car args) 'status?) status)
((eq? (car args) 'dead?) (eq? status 'dead))
((eq? (car args) 'alive?) (not (eq? status 'dead)))
((eq? (car args) 'kill!) (set! status 'dead))
(#t (apply last-continuation args)))))))
;;Define a function that will return a suspended coroutine created from given args and body forms
(define-syntax (define-coroutine stx)
(syntax-case stx ()
((_ (name . args) . body )
#`(define (name . args)
(make-generator
(lambda (#,(datum->syntax stx 'yield))
. body))))))我想要做的是实现一个异常处理程序(带有-处理程序),它调用(产)函数。这个想法是,第二个线程可以向线程发送一个计算协同线的信号,迫使它在运行时间太长时屈服。
我在args lambda中尝试了以下方法,它成功地在早期返回,但后来对coroutine (我的- coroutine 'dead?)的评估返回到coroutine处于“死状态”:
(with-handlers
([exn:break?
(lambda (break)
(yield 'coroutine-timeout))])
(break-enabled #t) ;register for yield requests from coroutine manager thread
(last-continuation last-value))))或者,我尝试了以下方法,但它没有生成一个可以应用于参数的过程:
(with-handlers
([exn:break?
(lambda (break)
(set! last-continuation (exn:break-continuation break))
(set! last-value 'coroutine-timeout)
(set! status 'suspended)
(last-return 'coroutine-timeout))])
(break-enabled #t) ;register for yield requests from coroutine manager thread
(last-continuation last-value))))我试图了解连续和异常是如何相互作用/阻塞的。好像我需要用参数吗?
如何成功地编写一个正确的信号处理程序,以便以后可以恢复协同工作呢?
编辑:我在这里混合元调(合作和抢占多线程)。但是,我的问题在我看来似乎是可能的(从外行的角度来看),因为我可以从异常处理程序中评估在协同器中定义的函数(包括(产生))。实际上,我试图在我的工作线程中限制资源饥饿,并减轻某种类型的死锁(其中,任务1只能在任务2运行之后才能完成,并且没有可供任务2运行的空闲线程)。
我为这些协同函数编写了一个函数,该函数是以go的goroutines为模型的。我假设它们通过在它们控制的底层代码中进行协作的产量检查来实现它们在单线程上的异步行为。也许它按照您的建议在VM中运行,并且有检查,也许它们的操作符有检查。不管是什么情况,我都试图用不同的策略来实现类似的行为。
发布于 2018-10-29 04:54:35
至于“连续和异常是如何相互作用/阻止的”,重要的是要知道异常是使用分隔的连续实现的。特别是,例外制度利用了延续障碍。这两个都是在球拍参考§1.1.12 Prompts、定界延续和障碍中介绍的。
延续屏障是另一种连续框架,它禁止以另一种方式替换当前的延续。…因此,延拓屏障防止“向下跳”到由屏障保护的延续中。某些操作会自动安装障碍;特别是,当调用异常处理程序时,延续屏障将禁止处理程序的继续捕获过去的异常点。
你可能还想看一些关于稍后在评估模型部分和控制流段的例外情况的资料,其中引用了一篇关于这个主题的学术论文。差异在call-with-exception-handler和with-handlers之间也与从异常处理程序中捕获连续性相关。
但是,从根本上说,延续屏障防止对中止的延续使用异常处理程序,并可能在以后继续:您应该使用延续屏障并直接提示。
更广泛地说,我建议您看看Racket对并发的大量现有支持。即使您希望将协同机制作为一个实验来实现,它们对于启发和实现技术的示例也是有用的。Racket附带派生结构,如发动机 (“可被定时器或其他外部触发器抢占的进程”)和发电机,以及基本的构建块-- 绿线和可同步事件 (它们基于并发ML模型)。
发布于 2018-10-25 11:21:45
你问题的要点是:
如何实现coroutines的异常处理程序,这样第二个线程就可以向计算协同线的线程发送信号,迫使它在运行时间过长时屈服。
再一次:
如何成功地编写一个正确的信号处理程序,以便以后可以恢复协同工作呢?
在我看来,你并没有把合作和先发制人的多任务区分开来,因为你似乎想把协同(合作)和超时(先发制人)结合起来。(您还提到了线程,但似乎将它们与协同工作混为一谈。)
有了协同多任务处理,就没有办法强迫其他人停止运行;因此,就有了“合作”这个绰号。
对于先发制人的多任务处理,您不需要屈服,因为当您分配的时间用完时,调度程序会抢占您的位置。调度程序还负责保存您的继续,但它不是(调度程序)当前的延续,因为调度程序与用户线程完全独立。
也许最接近你提议的是通过投票模拟先发制人的多任务处理。每个(模拟的)时间步骤(即VM指令)都需要检查运行线程是否接收到任何中断/信号并处理它们。
https://stackoverflow.com/questions/52978631
复制相似问题