On Thu, 15 May 2008, Andriy Gapon wrote:

> With current libthr behavior the GUI thread would never have a chance to get
> the mutex as worker thread would always be a winner (as my small program
> shows).

The example you gave indicates an incorrect mechanism being used for the
GUI to communicate with this worker thread.  For the behavior you desire,
you need a common condition that lets both the GUI and the work item
generator indicate that there is something for the worker to do, *and*
you need seperate mechanisms for the GUI and work item generator to add
to their respective queues.

Something like this (could be made even better with a little effor):

        struct worker_queues_s {
                pthread_mutex_t         work_mutex;
                struct work_queue_s     work_queue;

                pthread_mutex_t         gui_mutex;
                struct gui_queue_s      gui_queue;

                pthread_mutex_t         stuff_mutex;
                int                     stuff_todo;
                pthread_cond_t          stuff_cond;
        };
        struct worker_queue_s wq;

        int
        main(int argc, char *argv[]) {
                // blah blah
                init_worker_queue(&wq);
                // blah blah
        }

        void
        gui_callback(...) {
                // blah blah

                // Set up GUI message

                pthread_mutex_lock(&wq.gui_mutex);
                // Add GUI message to queue
                pthread_mutex_unlock(&wq.gui_mutex);

                pthread_mutex_lock(&wq.stuff_mutex);
                wq.stuff_todo++;
                pthread_cond_signal(&wq.stuff_cond);
                pthread_mutex_unlock(&wq.stuff_mutex);

                // blah blah
        }

        void*
        work_generator_thread(void*) {
                // blah blah

                while (1) {
                        // Set up work to do

                        pthread_mutex_lock(&wq.work_mutex);
                        // Add work item to queue
                        pthread_mutex_unlock(&wq.work_mutex);

                        pthread_mutex_lock(&wq.stuff_mutex);
                        wq.stuff_todo++;
                        pthread_cond_signal(&wq.stuff_cond);
                        pthread_mutex_unlock(&wq.stuff_mutex);
                }

                // blah blah
        }
        
        void*
        worker_thread(void* arg) {
                // blah blah

                while (1) {
                        // Wait for there to be something to do
                        pthread_mutex_lock(&wq.stuff_mutex);
                        while (wq.stuff_todo < 1) {
                                pthread_cond_wait(&wq.stuff_cond,
                                                  &wq.stuff_mutex);
                        }
                        pthread_mutex_unlock(&wq.stuff_mutex);

                        // Handle GUI messages
                        pthread_mutex_lock(&wq.gui_mutex);
                        while (!gui_queue_empty(&wq.gui_queue) {
                                // dequeue and process GUI messages
                                pthread_mutex_lock(&wq.stuff_mutex);
                                wq.stuff_todo--;
                                pthread_mutex_unlock(&wq.stuff_mutex);
                        }
                        pthread_mutex_unlock(&wq.gui_mutex);

                        // Handle work items
                        pthread_mutex_lock(&wq.work_mutex);
                        while (!work_queue_empty(&wq.work_queue)) {
                                // dequeue and process work item
                                pthread_mutex_lock(&wq.stuff_mutex);
                                wq.stuff_todo--;
                                pthread_mutex_unlock(&wq.stuff_mutex);
                        }
                        pthread_mutex_unlock(&wq.work_mutex);
                }

                // blah blah
        }

This should accomplish what you desire.  Caution that I haven't
compiled, run, or tested it, but I'm pretty sure it's a solid
solution.

The key here is unifying the two input sources (the GUI and work queues)
without blocking on either one of them individually.  The value of
(wq.stuff_todo < 1) becomes a proxy for the value of
(gui_queue_empty(...) && work_queue_empty(...)).

I hope that helps,
Brent

-- 
Brent Casavant                  Dance like everybody should be watching.
www.angeltread.org
KD5EMB, EN34lv
_______________________________________________
freebsd-stable@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-stable
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to