Создание нескольких процессов для обработки множества соединений на основе сокетов в Clozure Common Lisp

У меня есть следующее:

(defun serve (&key (port 80) (handler #'IDENTITY))
  (WITH-OPEN-SOCKET 
    (socket :LOCAL-PORT port 
            :LOCAL-HOST "localhost" 
            :CONNECT :PASSIVE 
            :REUSE-ADDRESS t)
    (flet ((handle-connection ()
                              (with-open-stream 
                                (stream (ACCEPT-CONNECTION socket :wait t))
                                (funcall handler stream))))
          (loop (handle-connection)))))

Когда приходит соединение, оно принимается, и поток передается обработчику. Процесс ожидает (блокирует) обработчик. Таким образом, следующее соединение обрабатывается, когда обработчик возвращается.

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

Я попытался сделать:

(PROCESS-RUN-FUNCTION (gensym) 
  (lambda () (funcall handler stream)))

вместо просто (funcall handler stream), но это заканчивается ошибкой, потому что поток недоступен к моменту вызова обработчика. Очевидно, потому что with-open-stream к тому времени вышел, а поток выходит за рамки и, следовательно, (может быть?) GC.

Затем я попробовал:

(loop 
  (PROCESS-RUN-FUNCTION (gensym) 
    (lambda () 
      (format t "new process ") 
      (handle-connection))))

вместо просто (loop (handle-connection)), который убегает, порождая новые процессы со скоростью цикла, потому что ожидание в части сокета больше не блокирует выполнение.

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


person Capstone    schedule 14.01.2017    source источник


Ответы (1)


Не стоит работать с потоком, одновременно закрывая его.

Также не следует использовать в процессе переменные, которые получают значения извне процесса. Передайте все данные, которые вам нужны, функции, которая работает как процесс, через аргументы.

(let ((accepted-stream (acception-connection socket      ; just take the stream
                                             :wait t)))

  (process-run-function               ; run a function as a process/thread

    (gensym "CONNECTION-HANDLER-")    ; generate a name

    (lambda (stream)                  ; take the one argument, the stream
      (unwind-protect (progn ...)     ; do something, with clean-up
        (close stream)))              ; make sure the stream gets closed

    accepted-stream))                 ; pass the stream, which then gets passed to
                                      ; the lambda function
person Rainer Joswig    schedule 14.01.2017