From owner-freebsd-threads@FreeBSD.ORG Thu May 15 19:51:27 2008 Return-Path: Delivered-To: freebsd-threads@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2BB9E1065675; Thu, 15 May 2008 19:51:27 +0000 (UTC) (envelope-from b.j.casavant@ieee.org) Received: from yeppers.tdkt.org (skyline.tdkt.org [209.98.211.67]) by mx1.freebsd.org (Postfix) with ESMTP id A7C588FC13; Thu, 15 May 2008 19:51:26 +0000 (UTC) (envelope-from b.j.casavant@ieee.org) Received: from pkunk.americas.sgi.com (cfcafwp.sgi.com [192.48.179.6]) (authenticated bits=0) by yeppers.tdkt.org (8.12.11/8.12.11/erikj-OpenBSD) with ESMTP id m4FJpKq2014745; Thu, 15 May 2008 14:51:23 -0500 (CDT) Date: Thu, 15 May 2008 14:51:08 -0500 (CDT) From: Brent Casavant X-X-Sender: bcasavan@pkunk.americas.sgi.com To: Andriy Gapon In-Reply-To: <482BF5EA.5010806@icyb.net.ua> Message-ID: References: <482B0297.2050300@icyb.net.ua> <482BBA77.8000704@freebsd.org> <482BF5EA.5010806@icyb.net.ua> User-Agent: Alpine 1.10 (BSF 962 2008-03-14) Organization: "Angeltread Software Organization" MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Cc: freebsd-stable@freebsd.org, David Xu , freebsd-threads@freebsd.org Subject: Re: thread scheduling at mutex unlock X-BeenThere: freebsd-threads@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Brent Casavant List-Id: Threading on FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 15 May 2008 19:51:27 -0000 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