Domanda

I'm trying to make my program to do this:

  • Take input: nrNodes NrWorkers
  • 3 threads(workers) can only access at a moment the list(read), but only 1 can write.
  • when 5 nodes have been done(sqrt value), it should stop and let in the cleaner thread which cleans in the linked list all done nodes, than it gives the acces back to the remaining threads which have work

    Thread1: get semaphoreSlot(); work; send signal if conition acomplished; until list parsed;

    Thread2: wait signal; clean; return access to thread1;

    After clean: problem encountered; stops, without exiting;

Code :

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <math.h>
#include <semaphore.h>

#define doneLimit 5

struct dataBlock{
    struct node *root;
    int listSize;
    int forIndex;
};

struct node { // std linked list node
    int value;
    int worker;
    struct node *next;
};

int done = 0;

sem_t sem;

pthread_mutex_t mutp;   // mutex
pthread_cond_t  condvar;   //condvar

void *deleteDoneNodes(void *n){
    pthread_cond_wait( &condvar, &mutp );
    struct node *root = n;
    struct node *it = root;
    struct node *prev = NULL;

    printf("Cleaning 1's \n");   
        do{
            if(it->value == 1){
                struct node *next = it->next;
                if (prev != NULL) {
                    prev->next = next;
                }
                if (it == root) {
                    root = next;
                }
                free(it);
                it = next;
            }
            else {
                prev = it;
                it = it->next;
            }
        }while(it !=  NULL);
        done = 0;

    pthread_exit(NULL);
}

void * worker( void *data ){
    // get list
    int wFlag;
    struct dataBlock *inData = ( struct dataBlock * ) data;
    struct node *root = inData->root;
    int forIndex = inData->forIndex;
    free(data);

    // parse
    while(1){
        if( sem_wait( &sem )  != 0 ){
            printf( " > waiting...  \n" );
        }
        struct node *it = root;

        printf("    Thread >>>  %d  ---  %lu \n", forIndex, pthread_self() );
        do{
            wFlag = 0;
            pthread_mutex_lock( &mutp );
            if( forIndex == it->worker ){
                if( it->value > 2 ){

                    while( it->value != 1 ){
                        it->value = sqrt(it->value);
                        }
                        printf("! node done\n");
                    pthread_mutex_unlock( &mutp );
                    wFlag += 1;
                    done += 1;
                    if( done == doneLimit ){ // limit 5
                        pthread_cond_signal( &condvar );
                    }
                    break;
                }
            }
            else{
                printf("...parsed done node. \n");
            }
            it = it->next;
            pthread_mutex_unlock( &mutp );
        }while(it !=  NULL);

        sem_post(&sem); 
        sleep(1); // "create" concurrancy envi. 
        if ( wFlag == 0 ){
            break;
        }
    }
    pthread_exit(NULL);
}



int main( int argc, char *argv[] ){
    if ( argc != 3 ){
        printf( "Programm must be called with \n NR of elements and NR of workers! \n " );
        exit( 1 );
    }
    int i;
    struct node *root;
    struct node *iterator;  

//prepare list for task
    int listSize = atoi(argv[1]);
    int nrWorkers = atoi(argv[2]);
    root = malloc(sizeof( struct node) );

    root->value = rand() % 100;
    root->worker = 0;
    iterator = root;

    for( i=1; i<listSize; i++ ){
        iterator->next = malloc(sizeof(struct node));
        iterator = iterator->next;
        iterator->value = rand() % 100;
        iterator->worker = i % nrWorkers;
        printf("node #%d worker: %d  value: %d\n", i, iterator->worker,iterator->value);
    }
    iterator->next = NULL;
    printf("? List got populated\n");
// init semaphore > keeps max 3 threads working over the list

    if( sem_init(&sem,0,3) < 0){
      perror("semaphore initilization");
      exit(0);
    }

// Create all threads to parse the link list
    int ret;    
    pthread_mutex_init( &mutp,NULL );
    pthread_cond_init( &condvar, NULL );

    pthread_t w_thread;
    pthread_t* w_threads = malloc(nrWorkers * sizeof(w_thread));

    for( i=0; i < nrWorkers; i++ ){         
        struct dataBlock *data = malloc(sizeof(struct dataBlock));
        data->root = root;
        data->listSize = listSize;
        data->forIndex = i;
        ret = pthread_create ( &w_threads[i], NULL, worker, (void *) data );
        if( ret ) {
            perror("Worker creation fail \n");
            exit(2);    
        }   
    } 
// Create Cleaning thread
    pthread_t c_thread;
    ret = pthread_create(&c_thread, NULL, deleteDoneNodes, (void *) root);
    if ( ret ){
        printf("Cleaner cration fail \n");
    }

// Join threads
    for ( i = 0; i < nrWorkers; i++ ){
        pthread_join(w_threads[i],NULL);
    }

    iterator = root;
    for ( i = 0; i < listSize; i++){
        printf("val: %d  worker: %d _  \n", iterator->value, iterator->worker);
        iterator = iterator->next;
    }

    free( root );
    pthread_mutex_destroy( &mutp );
    pthread_cond_destroy( &condvar );
    sem_destroy( &sem );

    return 0;
}

PS: it works ./s 1 1 ./s 1 4 ./s 4 4 ./s 4 1

It fails after the call of the cleaner: it fails at ./s x n, when x >= 5

È stato utile?

Soluzione

At least you are not correctly handling the usage of condition variable and mutex.

The mutex shall be locked by the thread calling pthread_cond_wait() prior to calling the latter.

Verbatim from man pthread_cond_wait:

pthread_cond_wait atomically unlocks the mutex (as per pthread_unlock_mutex) and waits for the condition variable cond to be signaled. The thread execution is suspended and does not consume any CPU time until the condition variable is signaled. The mutex must be locked by the calling thread on entrance to pthread_cond_wait. Before returning to the calling thread, pthread_cond_wait re-acquires mutex (as per pthread_lock_mutex).

Also the mutex is locked after returning form the call to pthread_cond_wait() and must be unlocked then somewhere sometime.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top