Subj : class for function calls that are not thread safe To : comp.programming.threads From : Markus Elfring Date : Mon Jan 10 2005 06:58 pm Another try with changed predicate handling ... A follow-up / continuation for this discussion: http://groups.google.de/groups?threadm=OtKbb.127587$mp.64498@rwcrnsc51.ops.a sp.att.net http://groups.google.de/groups?threadm=40ed1d8f.0311060940.73c45e36%40postin g.google.com /*************************************************************************** ** * * Contents: * Draft for a solution to the exercise "utility to make calls for * thread unsafe functions easier" * Each unsafe function category can be called by the same single thread. * * Copyright: * © Markus Elfring * * Comments: * How do you think about this approach? * Is it useful to be integrated into other libraries? * **************************************************************************** */ #include #include #include "pthread.h" struct job { void* (*function) (void*); void* arg; void** result; }; struct predicate { pthread_mutex_t mutex; pthread_cond_t cond; bool value; }; struct rule { predicate condition; job action; }; struct monitored_executor { job* job; pthread_t thread; predicate free; }; void job_do (job* j) { if (j) { void* jobresult = *(j -> function) (j -> arg); if (j -> result) { /* The caller is interested in the return value. */ *(j -> result) = jobresult; } } } int wait_until (predicate* p, bool const flag) { if (p) { /* Acquire a lock. */ int result = pthread_mutex_lock(&(p -> mutex); if (result == 0) { while (p -> value != flag) { if (result = pthread_cond_wait(&(p -> cond), &(p -> mutex))) { pthread_mutex_unlock(&(p -> mutex)); return result; } } } /* end of if expression */ return result; } else { return EINVAL; } /* end of if expression */ } void* executor_leave (void* /* parameter */) { pthread_exit(NULL); return NULL; } void* executor_run (void* parameter) { int result = 0; monitored_executor* e = (monitored_executor*) parameter; while (true) { /* Did another thread request to do anything? */ if (result = wait_until(&(e -> free), false) { /* Can be more done to handle this error situation? */ break; } else { /* Perform the job that was placed into the queue. */ job_do(e -> _job); if (result = pthread_mutex_lock(&(e -> free.mutex))) { /* Can be more done to handle this error situation? */ break; } else { me -> free.value = true; if (result = pthread_mutex_unlock(&(e -> free.mutex))) { /* Can be more done to handle this error situation? */ break; } else { if (result = pthread_cond_signal(&(e -> free.cond))) { /* Can be more done to handle this error situation? */ break; } } /* end of if expression */ } /* end of if expression */ } /* end of if expression */ } /* end of while loop */ return (void*) result; } int monitored_executor_do (monitored_executor* e, job* next_work) { if (e && next_work && (next_work -> function)) { /* Is the other thread ready to do anything for us? */ int result = wait_until(&(e -> free), true); if (result == 0) { e -> job = next_work; e -> free.value = false; if ((result = pthread_mutex_unlock(&(e -> free.mutex))) == 0) { result = pthread_cond_signal(&(e -> free.cond)); } } /* end of if expression */ return result; } else { return EINVAL; } /* end of if expression */ } int monitored_executor_new (monitored_executor** e) { if (e) { monitored_executor* me = (monitored_executor*) malloc(sizeof(monitored_executor)); if (me) { int result = pthread_mutex_init(&(me -> free.mutex), NULL); if (result) { free(me); } else { if (result = pthread_cond_init(&(me -> free.cond), NULL)) { pthread_mutex_destroy(&(me -> free.mutex)); free(me); } else { me -> free.value = true; if (result = pthread_create(&(me -> thread), NULL, & executor_run, me)) { pthread_cond_destroy(&(me -> free.cond)); pthread_mutex_destroy(&(me -> free.mutex)); free(me); } else { *e = me; } /* end of if expression */ } /* end of if expression */ } /* end of if expression */ return result; } else { return ENOMEN; } /* end of if expression */ } else { return EINVAL; } /* end of if expression */ } int monitored_executor_delete (monitored_executor* e) { if (e) { /* Did the other thread finish its work? */ int result = wait_until(&(e -> free), true); if (result) { pthread_mutex_unlock(&(e -> free.mutex)); } else { job* executor_exit = (job*) malloc(sizeof(job)); if (executor_exit) { executor_exit -> function = & executor_leave; executor_exit -> result = NULL; /* The other thread must return from the function to stop its execution. A cancellation request is avoided here. */ if (result = monitored_executor_do(e, executor_exit)) { pthread_mutex_unlock(&(e -> free.mutex)); } else { pthread_mutex_unlock(&(e -> free.mutex)); /* Release memory and pthread's resources. */ pthread_cond_destroy(&(e -> free.cond)); pthread_mutex_destroy(&(e -> free.mutex)); free(e); } /* end of if expression */ free(executor_exit); /* Release memory. */ } else { pthread_mutex_unlock(&(e -> free.mutex)); result = ENOMEN; } /* end of if expression */ } /* end of if expression */ return result; } else { return EINVAL; } /* end of if expression */ } .