thread scheduling at mutex unlock
Brent Casavant
b.j.casavant at ieee.org
Thu May 15 19:51:27 UTC 2008
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
More information about the freebsd-stable
mailing list