I realized after i sent that email that it was a little rushed, and too unqualified. So in the interest of completeness (and to avoid possible misuse), the following addendum to the last post:
The code provided assumed a background program, i.e., not a GUI or a program running with a main loop, since the call to g_async_queue_pop() in the main routine is blocking. As written, this code should absolutely NOT be used in a program where a main loop is expected to remain responsive. However, with a little modification, the algorithm can easily be made non-blocking and usable in a GUI: - Remove all references to the async queue commQ. - In finishThreads(), instead of returning the answer via commQ, use g_idle_add() to pass the result back to the main loop. (write a new routine that takes the result and presents it back to the user, whatever that means.) In general, too, the following warnings must accompany this code: - Case is not handled when code is called a second time before the first call has completed, i.e., it is not re-entrant as written. Calling a 2nd time before 1st execution has completed will cause indecipherable havoc; either handle this case, or disallow it. - There are memory leaks. And, while I'm here, a couple of relevant guidelines to writing multi-threaded code: - Use as few locks as possible in the threads. In the example provided, the stored result could have been referred to directly (added to) in each executing thread, using a lock around the summation. Instead, the solution provides for each thread to access to a single (and unique) element of an array of float values holding the summing result, while the finishThreads sums each thread's result once all threads have completed, returning this single value to the main routine/loop. In this manner, no lock is necessary here in computing the result, guaranteeing a faster completion. - Whatever code must exist inside a lock, make it absolutely as small as possible. The more code that exists inside a lock, the greater the chance that other threads will get stuck waiting on the lock to be free. The more threads that must sit and wait for a lock to be free, the less the point of having made the code multi-threaded in the first place (since, by definition, locked code means only one can execute at a time, not much different than writing in-line...). In the provided solution, a single lock is required around g_queue_pop_head() (which executes very fast), making the likelihood of a thread having to wait on the lock to be free very low indeed. cheers, richard 2010/7/23 richard boaz <[email protected]> > this is how i do it (not using pools), i have modified my code for your > purposes, though it's probably wrong somewhere in the implementation details > (i didn't even compile it), but i leave that to you. > > this is very easily generalizable to do any kind of background work on a > "list" of items. > > richard > > === BEGIN code snippet === > > { // in the main routine > gfloat *retPtr, tot_err; > GQueue *threadsQ = g_queue_new(); // Q holding list of data items to > process > data_t data[N_DATAPOINTS]; // data items to process > fill_the_data_array(data); > for(i = 0; > i < N_DATAPOINTS; > i++) > { > g_queue_push_head(threadsQ, &data[i]); // put data item onto Q for > processing > } > g_thread_init(NULL); > commQ = g_async_queue_new(); // create comms Q > threadsProc(threadsQ, maxThreads); // initiate threads > retPtr = (g_float*) g_async_queue_pop(commQ); // sit and wait for all > threads in threadsProc() to complete... > tot_err = *retPtr; // the answer > } > > // all the rest in a different source file... > > static GQueue *threadsQ; // Q holding the data to process > static int numThreads; // number of threads (and a counter too) > static g_float *tot_err; // array of g_float, one element per thread > static g_float total_errors; // total errors, added up, returned to main > static GStaticMutex QMutex = G_STATIC_MUTEX_INIT; // mutex to read Q > > typedef struct _THREADARGS > { // structure of arguments to thread proc > GThreadFunc returnFunc; > int threadNum; > } THREADARGS; > > static void finishThreads() > { // called once a thread has finished its work > numThreads--; > if (!numThreads) > { // return to main routine > int i; > g_float retValue = 0; > for (i = 0;i<numThreads; i++) > retValue += tot_err[i]; > total_errors = retValue; > g_async_queue_push(commQ, &total_errors); > } > } > > static data_t *get_data() > { // get the next data item off the Q to process, called by _addData() > data_t *data; > g_static_mutex_lock(&QMutex); > data = g_queue_pop_head(threadsQ); > g_static_mutex_unlock(&QMutex); > return (data); > } > > static void _addData(THREADARGS *threadArgs) > { // processing thread > int threadNum = threadArgs->threadNum; > GThreadFunc retFunc = threadArgs->returnFunc; > data_t *data = get_data(); // get a data item to process > while (data) > { > tot_err[threadNum] += calc_error(data); > data = get_data(); // until no more to do > } > (*(retFunc))(NULL); > } > > void threadsProc(GQueue *q, int nThreads) > { > int i; > numThreads = nThreads; > tot_err = calloc(numThreads, sizeof(g_float)); > threadsQ = q; > for(i=0;i<numThreads;i++) > { > THREADARGS *threadArgs; > threadArgs = calloc(1, sizeof(THREADARGS)); > threadArgs->returnFunc = (GThreadFunc) finishThreads; > threadArgs->threadNum = i; > g_thread_create((GThreadFunc) _addData, (void *) threadArgs, FALSE, NULL); > } > } > > === END code snippet === > > > 2010/7/23 Øystein Schønning-Johansen <[email protected]> > > I tried, and the new problem is now: >> >> pool = g_thread_pool_new( my_calc, (gpointer) &common, 8, FALSE, &err ); >> >> for (i = 0; i < n_tot; i++ ) >> g_thread_pool_push( pool, &store[i], &err ); >> >> g_thread_pool_free( pool, FALSE, TRUE ); >> >> When I run this code, it continues without waiting for the threads to >> complete. I expected that the g_thread_pool_free function would make it >> wait >> for all threads to complete before the program code continues, however >> it does not! How can I make it wait? >> >> (Yes, I added a static mutex in my_func. I'm convinced that I need it. ) >> >> -Øystein >> _______________________________________________ >> gtk-list mailing list >> [email protected] >> http://mail.gnome.org/mailman/listinfo/gtk-list >> > >
_______________________________________________ gtk-list mailing list [email protected] http://mail.gnome.org/mailman/listinfo/gtk-list
