Как получить текущее продолжение потока из обработчика исключений - PullRequest
0 голосов
/ 25 октября 2018

Этот код действительно расширяет границы моего понимания, поэтому терпите меня.

Ранее я реализовал сопрограммы в 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))))))

Что я хочу сделать, так этореализовать обработчик исключений (with-handlers), который вызывает функцию (yield).Идея состоит в том, что второй поток может посылать сигнал потоку, оценивая сопрограмму, заставляя ее выдавать, когда он работает слишком долго.

Я пробовал следующее в лямбде args, который успешно вернулся рано, но позжеоценки сопрограммы (my-coroutine 'dead?) вернули, что сопрограмма находилась в' dead состоянии:

                (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))))

Я пытаюсь понять, как продолжения и исключения взаимодействуют / блокируют друг друга.Кажется, мне может понадобиться как-то использовать параметры?

Как мне успешно написать обработчик сигнала, который будет (давать) правильно, чтобы я мог возобновить сопрограмму позже?

Редактировать: Ясмешивание метафор здесь (кооперативная и упреждающая многопоточность).Тем не менее, мой вопрос кажется мне возможным (с точки зрения непрофессионала), так как я могу оценить функции, определенные в моей сопрограмме (включая (yield)) из обработчика исключений.По сути, я пытаюсь ограничить нехватку ресурсов в моих рабочих потоках, а также уменьшить определенный класс тупиков (где задача 1 может быть завершена только после выполнения задачи 2, и нет свободных потоков для задачи 2 для выполнения).

Я написал (go) функцию для этих сопрограмм, которая смоделирована после go-подпрограмм go.Я предполагаю, что они достигают своего асинхронного поведения в отдельных потоках, имея совместные проверки доходности в основном коде, которым они управляют.Возможно, он работает в виртуальной машине, как вы предложили, и есть проверки, возможно, их операторы имеют проверки.Как бы то ни было, я пытаюсь добиться похожего поведения с другой стратегией.

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

Что касается того, «как продолжения и исключения взаимодействуют / блокируют друг друга», важно знать, что исключения реализуются с использованием продолжений с разделителями.В частности, система исключений использует барьеры продолжения .Оба они представлены в справочнике Racket §1.1.12 Подсказки, разделенные продолжения и барьеры :

Барьер продолжения - это другой тип кадра продолжения, который запрещает определенные заменытекущее продолжение с другим.… Таким образом, барьер продолжения предотвращает «скачки вниз» в продолжение, защищенное барьером.Некоторые операции устанавливают барьеры автоматически;в частности, когда вызывается обработчик исключений, барьер продолжения запрещает продолжению обработчика захватывать продолжение после точки исключения.

Вы также можете захотеть увидеть материал об исключениях из позже в разделе оценочной модели и в разделе потока управления *1013*, в котором цитируется академическая статья по этому вопросу.Различия между call-with-exception-handler и with-handlers также имеют отношение к получению продолжений из обработчиков исключений.

Однако, по сути, барьер продолжения не позволяет использовать обработчики исключений для продолжений, которые вы прерываете и которые впоследствии могут возобновить: вам следует использовать барьеры продолжения и запросы непосредственно для этого.

В более широком смысле, я бы предложилчто вы посмотрите на существующую поддержку Racket для параллелизма.Даже если вы хотите реализовать сопрограммы в качестве эксперимента, они будут полезны для вдохновения и примеров методов реализации.Racket поставляется с производными конструкциями, такими как engine («процессы, которые могут быть прерваны таймером или другим внешним триггером») и генераторы , в дополнение к фундаментальным строительным блокам, зеленые потоки и синхронизируемые события (основанные на модели Concurrent ML).

0 голосов
/ 25 октября 2018

Суть вашего вопроса:

Как я могу реализовать обработчик исключений для сопрограмм, чтобы второй поток мог посылать сигнал потоку, оценивающему сопрограмму, заставляя его выдавать, когда егоработает слишком долго.

И еще раз:

Как я могу успешно написать обработчик сигнала, который будет (давать) правильно, чтобы я мог возобновить сопрограмму позже?

Мне кажется, что вы не разделяете чисто многозадачность на основе кооперативности и вытеснения, так как вы, кажется, хотите объединить сопрограммы (кооперативность) с тайм-аутами (вытеснение).(Вы также упоминаете потоки, но, кажется, связываете их с сопрограммами.)

С кооперативной многозадачностью нет способа заставить кого-либо другого прекратить работу;следовательно, прозвище «кооперативное».

С упреждающей многозадачностью вам не нужно уступать, потому что планировщик выгрузит вас по истечении выделенного времени.Планировщик также отвечает за сохранение вашего продолжения, но оно не является текущим продолжением (планировщика), так как планировщик полностью отделен от пользовательского потока.

Возможно, наиболее близкая вещь к тому, что вы предлагаете, - это имитация вытесняющегомногозадачность через опрос.Каждый (смоделированный) временной шаг (т. Е. Инструкция VM) для симуляции необходимо проверять, были ли получены прерывания / сигналы работающим потоком, и обрабатывать их.

...