views:

92

answers:

2

I have an assignment in class that requires us to use POSIX threads and create n*(n-1)/2 of them to process a dataset of n elements.

You can think of it as basically the classical "handshake" in probability.

I know that for a large data set it's going to make the application CPU-bound and eventually it will spend so much time context switching that it will be useless, but the assignment requires us to do this.

However, my loop to create all the threads ceases creating them after a while.

For the code below, I will see output like:

making thread
thread start
thread done
made thread 1944
making thread
thread start
thread done
made thread 1945
making thread
thread start
thread done
made thread 1946
making thread

for a while, but then I will stop seeing the "thread start" and "thread done" messages, and only see the "making thread, made thread" messages.

Here is the loop that creates the threads:

    int tCtr = 0;
    tArr = (pthread_t*)malloc(((numbers_read) * (numbers_read - 1)/2) * sizeof(pthread_t));
    for(i=0; i<numbers_read; i++){
        int j;
        for(j=i; j<numbers_read; j++){
            // n(n-1)/2
            if(i != j){
                printf("making thread\n");
                struct comparison_struct *data;
                data = (struct comparison_struct *)malloc(sizeof(struct comparison_struct));
                data->i_value = &numbers[i];
                data->j_value = &numbers[j];
                data->i_arr_entry = &wArr[i];
                data->j_arr_entry = &wArr[j];
                pthread_create(&tArr[tCtr], NULL, compare_thread, (void *)data);
                printf("made thread %d\n", tCtr);
                tCtr++;
            }
        }
    }
    for(i=0; i<tCtr; i++){
        pthread_join(tArr[i], NULL);
    }
    free(tArr);

and here is the subroutine containing the thread code:

void *compare_thread(void *vData) {
    printf("thread start\n");
    struct comparison_struct *data;
    data = (struct comparison_struct *)vData;
    if(*data->i_value <= *data->j_value){
        *data->i_arr_entry = 0;
    } else {
        *data->j_arr_entry = 0;
    }
    free(vData);
    printf("thread done\n");
    return NULL;
}

Anybody have any ideas? I'm new to pthreads and having trouble figuring it out.

I know that if I put the pthread_join call immediately after the pthread_create, the application works - but then it blocks on every thread, which I'd assume would decrease performance because there will only ever actually be 2 threads running at a time.

+2  A: 

check the return value of pthread_create, maybe you are hitting a resource limit.

 pthread_create() will fail if:

 [EAGAIN]           The system lacked the necessary resources to create
                    another thread, or the system-imposed limit on the
                    total number of threads in a process
                    [PTHREAD_THREADS_MAX] would be exceeded.

 [EINVAL]           The value specified by attr is invalid.

If you are reaching a resource limit, you can try to make a thread that joins on the other threads, make a worker queue and give work to each of the threads via the queue, or if you control the resource limit of the system try to increase it.

Eld
Or for a Mickey Mouse fix to a Mickey Mouse problem, unroll the loop a little so that you create a few threads, then join all of them, then create a few more and so on. The assignment might say you have to create all those threads, but does it say you have to let them all run at once? ;-)
Steve Jessop
+1  A: 

if I put the pthread_join call immediately after the pthread_create ...then it blocks on every thread...there will only ever actually be 2 threads running at a time.

An alternative to joining the threads is to just create them as detached. Create and initialize a pthread_attr_t, set it detached and pass the attr in with your pthread_create call.

pthread_attr_t  attr;
int             ret;

ret = pthread_attr_init(&attr);
if (ret)
   // error .........

ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

for (....)
{
    //........
    ret = pthread_create(&tArr[tCtr], &attr, compare_thread, (void *)data);
    //.......
}

ret = pthread_attr_destroy(&attr);

There is also no requirement that a thread that creates another thread has to be the one to join it. You can create a thread just to join all other created threads. But that is probably going beyond the call of duty for this assignment.

Duck