[gambit-list] Graceful shutdown of running gambit process

Marc Feeley feeley at iro.umontreal.ca
Tue Apr 22 18:22:02 EDT 2008


What are the threads blocking on?  Apparently, just one thing  
(receiving the next request from the student over a socket).  It seems  
that you want the threads to wait on the occurrence of multiple events:

1) request from the student
2) termination request

This form of waiting can be achieved in several ways (condition  
variables, event queues, mailboxes, ...).  I suggest you use  
mailboxes.  The basic idea is this: you have 1 thread waiting for  
student requests and dispatching them to the appropriate thread by  
adding the request to that thread's mailbox.  The termination request  
simply adds a "termination" message to the mailbox of all the  
threads.  So you end up with code like this:

(define (server)
   (let ((accept-port (open-tcp-server 8000)))
     (let loop ()
       (let ((connection (read accept-port)))
         (if (not (eof-object? connection))
             (begin
               (handle connection)
               (loop)))))))

(define (handle connection)
   (let ((request (read-line connection)))
     ;; just send it to a random thread
     (let ((ws (map car (table->list workers))))
       (thread-send
        (list-ref ws (random-integer (length ws)))
        (make-normal-request request connection)))))

(define (terminate-all-workers)
   (let ((ws (map car (table->list workers))))
     (for-each (lambda (t)
                 (thread-send t 'terminate))
               ws)))

(define-type normal-request
   request
   connection)

(define (termination-request? msg)
   (eq? msg 'terminate))

(define (worker id)
   (pp (list 'worker id 'starting))
   (let loop ()
     (let ((msg (thread-receive)))
       (cond ((normal-request? msg)
              (pp (list 'worker id 'got 'normal-request))
              (close-port (normal-request-connection msg))
              (loop))
             ((termination-request? msg)
              (pp (list 'worker id 'got 'termination-request))
              (worker-termination))
             (else
              (pp (list 'unknown-message))
              (loop))))))

(define (worker-termination)
   (table-set! workers (current-thread))) ;; remove from workers

(define workers
   (list->table
    (map (lambda (id)
           (cons (thread-start! (make-thread (lambda () (worker id))))
                 #f))
         '(0 1 2 3))))

(thread-start! ;; terminate all workers in 10 seconds
  (make-thread
   (lambda ()
     (thread-sleep! 10)
     (terminate-all-workers))))

(server)

On 22-Apr-08, at 3:47 PM, Bradley Lucier wrote:

> Marc:
>
> My homework on the web system needs a way to shut down gracefully.   
> Perhaps you can recommend how to do this.
>
> I'm using Gambit-C 4.0a8 (yes, that's right, "a8") because it  
> doesn't have the GC bug that plagues long-running Gambit programs  
> that use keyword/optional/whatever arguments in more recent versions  
> of Gambit.
>
> The program handles up to 1000 students at a time, with > 800  
> threads (one for each concurrent student) running an hour or so  
> before homework is due ;-).  Each Gambit process (there's one  
> application running for each course) starts up 5 Maple processes as  
> back-end servers.  It uses a very simple method to store student  
> results---when a student goes from one problem to another or from  
> one problem set to another, or when a student logs out or is timed  
> out for inactivity, it uses pretty-print to write the student's  
> current data to a file, and then uses RCS to archive the difference  
> between the current version and the previous one.
>
> Especially near the beginning of each semester, students add and  
> drop the course, and move from one section to another.  Currently, I  
> deal with this by killing the Gambit job and restarting it with the  
> new student lists, etc.  (Each student's data stays with the  
> student, if the student doesn't pay his/her fees and is temporarily  
> dropped from the course, all the pre-existing work is still there  
> when the student is re-registered for the class; if a student moves  
> sections, it only affects to which instructor a student's grades are  
> e-mailed.)  The restarting is effective, and takes only about 1  
> minute or two, but students currently working on the system have to  
> log back into the system after the system comes back up.
>
> The problem is that about once a semester, the program is killed as  
> a student's data is pretty-printed to the data file, so the data  
> that is written is only a truncated list.  The next time the program  
> attempts to load the data, there is an error, mutexes are abandoned,  
> etc.  A day or two goes by before it's really bad enough that  
> someone informs me there's a problem, and I eventually find the  
> problem, restore data from the RCS file, and go on our merry way.   
> (To my knowledge, no student data has ever been lost.)
>
> What I'd like is a way to send a signal to the program to shut down  
> gracefully---go to each thread, one by one, save the student data,  
> use RCS to back it up, and when you've done all that exit gracefully  
> (or now restart by reloading the class lists, etc.).  This should  
> avoid the rare but somewhat catastrophic failures I see when a  
> student data file is truncated.
>
> So, that's the background; any suggestions?
>
> Brad




More information about the Gambit-list mailing list