Question

Pseudo code:

void * thread_start(void *arg) {
    while (1) {
        /* for each column. Only run columns the thread_num
           is assigned to */
        column_count = thread_num;
        for (; column_count < dim - 1; column_count+=threads) {
             /* do thread work for data chunk */
        }

        /* barrier */
        barrier_result = pthread_barrier_wait(barrier);

        if (not_finished == 0) {
            /* finished */
            break;
            /* break while loop, end thread.
               The barrier is now broken because it is no longer
               getting called by this thread */
        }

        /* we are not finished, loop around and 
           do thread work on next data chunk */
    }
}

My issue with barriers is how do you deal with threads ending before other threads?

A barrier means every thread has to wait for every other thread.

What techniques are there for ensuring all threads end at the same time?

I tried continueing the loop but ignoring the "thread work", but in this case all 8 threads finish and there's no sensible way to tell the threads "your all done, you can all exit now"

Edit:

Algorithm:

  1. Run operations on segment of piece of data
  2. if the thread's segment of piece of data is finished terminate.
  3. Barrier wait.
  4. One thread replaces the piece of data with some new data
  5. repeat 1.

Edit 2:

Is there any elegant way to overwrite the barrier with a barrier that is one size smaller? (without putting a mutex around the barrier)

Était-ce utile?

La solution

You ensure threads end in the same time by the very nature of the program logic. If you algorithm calls for threads to exit at different times, then barriers are not a suitable concurrency control mechanism for that concrete algorithm.

EDIT:

You could atomically increment a "finished_count" and loop, not doing any work, other then participating the barrier, while that number is less than the barrier count (protecting read/writes to finished_count with appropriate mutexes).

EDIT: I'm not sure if I understand your added description well, I just wrote this based on your original code, maybe it'll work for you:

int finished_count;

void * thread_start(void *arg) {
    int finished = 0;

    while (1) {

        if (finished) {
            pthread_mutex_lock (&finished_lock);
            if (finished_count == 8) {
                pthread_mutex_unlock (&finished_lock);
                break;
            }
            pthread_mutex_unlock (&finished_lock);
        } else {
            /* for each column. Only run columns the thread_num
               is assigned to */
            column_count = thread_num;
            for (; column_count < dim - 1; column_count+=threads) {
                /* do thread work for data chunk */
            }

            /* set "finished" as appropriate */

            /* Check if we have just finished.  */
            if (finished) {
                pthread_mutex_lock (&finished_lock);
                ++finished_count;
                pthread_mutex_unlock (&finished_lock);
            }
        }

        barrier_result = pthread_barrier_wait(barrier);
    }

    return 0;
}

EDIT:

To clarify my comment above about copying over or reinitializing, POSIX says:

http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_barrier_init.html

The results are undefined if pthread_barrier_init() is called specifying an already initialized barrier.

and

Only the object referenced by barrier may be used for performing synchronization. The result of referring to copies of that object in calls to pthread_barrier_destroy() or pthread_barrier_wait() is undefined.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top