[SOLVED] When do you need more than 1 pthread barrier variable?
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
When do you need more than 1 pthread barrier variable?
Hello all
I am writing a multithreaded program using pthreads. I have a question abt the pthread_barrier functions, which are used to synchronize threads.
To give you a quick overview, to use pthread barrier functions,
a. declare a barrier variable alongwith its attribute and initialize it
Nope. The number of threads to wait at the barrier is defined in the count parameter to pthread_barrier_init(). You could, for example, have one barrier, and have eight threads wait until all of them are at that barrier.
Whether you want more than one barrier depends on the complexity and structure of your program. If you can't think of a reason to use more than one barrier, then you need only one barrier.
You could, for example, have one barrier, and have eight threads wait until all of them are at that barrier.
Yes, but not all the threads are necessarily synchronized together; one barrier is the minimal case, not the maximal one. You may be synchronizing in different groupings, in which case you will need more than one barrier.
The interesting question is what is the maximum number of barriers you could possibly need for a given number of threads. My intuition is n!/2, where n is the number of threads, but I suspect it might be more complicated than that, perhaps akin to a map coloring problem. I can't think of a situation in which a two-thread program would need more than one barrier, which I suspect is what the original poster was asking.
Heres a complete program I found on the web that uses multiple barriers. Firstly, I dont understand what it is doing. Secondly, if you change the statement pthread_barrier_wait (&barriers[j]) to pthread_barrier_wait (&barriers[1]), the program hangs. Why? Shouldn't barriers[1] mean that only 2 threads should wait on the barrier and the rest can continue?
Thanks,
Kshitij
Code:
/* Test of POSIX barriers. */
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NTHREADS 20
#define ROUNDS 20
static pthread_barrier_t barriers[NTHREADS];
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static int counters[NTHREADS];
static int serial[NTHREADS];
static void *
worker (void *arg)
{
void *result = NULL;
int nr = (int) arg;
int i;
for (i = 0; i < ROUNDS; ++i)
{
int j;
int retval;
if (nr == 0)
{
memset (counters, '\0', sizeof (counters));
memset (serial, '\0', sizeof (serial));
}
retval = pthread_barrier_wait (&barriers[NTHREADS - 1]);
if (retval != 0 && retval != PTHREAD_BARRIER_SERIAL_THREAD)
{
printf ("thread %d failed to wait for all the others\n", nr);
result = (void *) 1;
}
for (j = nr; j < NTHREADS; ++j)
{
/* Increment the counter for this round. */
pthread_mutex_lock (&lock);
++counters[j];
pthread_mutex_unlock (&lock);
/* Wait for the rest. */
retval = pthread_barrier_wait (&barriers[j]);
/* Test the result. */
if (nr == 0 && counters[j] != j + 1)
{
printf ("barrier in round %d released but count is %d\n",
j, counters[j]);
result = (void *) 1;
}
if (retval != 0)
{
if (retval != PTHREAD_BARRIER_SERIAL_THREAD)
{
printf ("thread %d in round %d has nonzero return value != PTHREAD_BARRIER_SERIAL_THREAD\n",
nr, j);
result = (void *) 1;
}
else
{
pthread_mutex_lock (&lock);
++serial[j];
pthread_mutex_unlock (&lock);
}
}
/* Wait for the rest again. */
retval = pthread_barrier_wait (&barriers[j]);
/* Now we can check whether exactly one thread was serializing. */
if (nr == 0 && serial[j] != 1)
{
printf ("not exactly one serial thread in round %d\n", j);
result = (void *) 1;
}
}
}
return result;
}
int main()
{
pthread_t threads[NTHREADS];
int i;
void *res;
int result = 0;
/* Initialized the barrier variables. */
for (i = 0; i < NTHREADS; ++i)
if (pthread_barrier_init (&barriers[i], NULL, i + 1) != 0)
{
printf ("Failed to initialize barrier %d\n", i);
exit (1);
}
/* Start the threads. */
for (i = 0; i < NTHREADS; ++i)
if (pthread_create (&threads[i], NULL, worker, (void *) i) != 0)
{
printf ("Failed to start thread %d\n", i);
exit (1);
}
/* And wait for them. */
for (i = 0; i < NTHREADS; ++i)
if (pthread_join (threads[i], &res) != 0 || res != NULL)
{
printf ("thread %d returned a failure\n", i);
result = 1;
}
if (result == 0)
puts ("all OK");
return result;
}
The program sets up 20 threads. Thread 0 waits on barriers 0 to n-1 in turn, thread 1 waits on barriers 1 to n-1, thread 2 waits on barriers 2 to n-1, and so on. That is why the barriers are initialized with different counts. The program tests to make sure the barriers are working (ie, no thread gets through the barrier until the correct number have reached it). The second part is checking that only one thread is nominated for PTHREAD_BARRIER_SERIAL_THREAD.
Now if you change them to all wait on the barriers[1], you totally mess up the logic of the program. Having a barrier count of 2 doesn't mean that the rest continue, it means that they will be let through in pairs. Not only that, but some threads will get to the second half (where they reuse the same barrier) while others are going through the first part. The reason for the deadlock (despite the fact that there are an even number of waits in total) is because the last thread to get scheduled is probably getting stuck at the first of the barrier_waits after all the rest have returned. In theory it won't get deadlocked every time, but chances are pretty slim (the code sections are short, so it is quite likely that threads will never be preempted, and the sequence is somewhat predictable). If you got rid of the serial check stage, it would not deadlock.
Having a barrier count of 2 doesn't mean that the rest continue, it means that they will be let through in pairs.
Thanks, that explains it. I have one final question:
If you want only one thread (a designated master thread) to wait for all other threads to reach a point, such that the master thread waits and the other threads only pass that point, can this be implemented using pthread barriers?
If you want only one thread (a designated master thread) to wait for all other threads to reach a point, such that the master thread waits and the other threads only pass that point, can this be implemented using pthread barriers?
That sounds more like a semaphore wait, with the 'master' waiting for a signal (post) from each of the other threads.
Code:
master
for n times
wait semaphore
n others
signal semaphore
However, if this is a situation where the other threads are supplying unbuffered information to the master thread, it may be you don't want the other threads to go too far. For example:
Code:
master
loop
do something else
wait barrier // waits for data to be produced
consume data // uses data
wait barrier // allows other threads to produce data
others
loop
produce data
wait barrier // allows master to consume data
do something else
wait barrier // waits until data consumed
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.