I’m trying to make my program to do this:
- Take input:
nrNodesNrWorkers - 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 workThread1:
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
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:Also the mutex is locked after returning form the call to
pthread_cond_wait()and must be unlocked then somewhere sometime.