I’m curious what I have done wrong, since my void *DeleteDoneNodes(node * n) doesn’t do anything, no error but no output neighter, so could anyone help me finding the root of my problem thank you.
Scenario: cmd line ./s m n
m number of nodes in list, n number of workingThreads should delete each nodes with node->value == 1, but it doesn’t do anything…
code:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <math.h>
#include <semaphore.h>
#define finishedNodes 5
#define workersLimitNr 3
int workingThreads = 0;
sem_t sem;
struct dataBlock{
struct node *root;
int listSize;
int forIndex;
};
struct node { // std linked list node
int value;
int worker;
struct node *next;
};
int slots = 0; // only 3 threads are allowed to access the list
int availableCheck(){ // check if thread can acces the list
if(slots < 3)
return 0;
else
return -1;
}
pthread_mutex_t mutp = PTHREAD_MUTEX_INITIALIZER; // mutex
pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; //condvar
void *deleteDoneNodes(struct node *n){ // T H I S I S T H E F U N C
struct node *root = n;
struct node *it;
it = root;
do{
if(it->value == 1){
struct node *tmp;
printf("DELETING: %d > %dn", it->value, it->worker );
root = root->next;
tmp = it;
it = it->next;
free(tmp);
}
else
it = it->next;
}while(it != NULL);
return NULL;
}
void * worker( void *data ){
struct dataBlock *inData = (struct dataBlock *) data;
struct node *root = inData->root;
int forIndex = inData ->forIndex;
free(data);
printf( "* Thread id: %lu forID: %d workerNode: n",pthread_self(),forIndex);
pthread_mutex_lock( &mutp );
if(availableCheck() < 0){
printf( " ^^^ List not available yet... n" );
pthread_cond_wait( &condvar, &mutp );
}
struct node *it = root;
printf( " _forID_ %dn |", forIndex );
do{
if(forIndex == it->worker){
printf("valid for sqrt forIndex %d == it->worker %dn",forIndex, it->worker );
if(it->value > 2){
while(it->value != 1)
it->value = sqrt(it->value);
// it->value = it->value - 1;
}
}
it = it->next;
}while(it != NULL);
pthread_cond_signal( &condvar ); //
pthread_mutex_unlock( &mutp );
return 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: %dn", i, iterator->worker,iterator->value);
}
iterator->next = NULL;
printf("? List got populatedn");
// 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_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("Thread creation fail");
exit(2);
}
}
deleteDoneNodes( root );
// printf( ">>>> %dn", root->value );
for ( i = 0; i < nrWorkers; i++ ){
pthread_join(w_threads[i],NULL);
}
// for ( i = 0; i < nrWorkers; i++){
// free(w_threads);
// }
iterator = root;
for ( i = 0; i < listSize; i++){
printf("val: %d worker: %d _ ", iterator->value, iterator->worker);
iterator = iterator->next;
}
free(root);
free(iterator);
return 0;
}
PS: It compiles / works error /warningless – tested with valgrind also.
Advertisement
Answer
Here’s an alternative version
void *deleteDoneNodes(struct node *n){
struct node *root = n;
struct node *it = root;
struct node *prev = NULL;
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);
return root;
}
The main changes are:
- Handling removal of an item from the middle of the list. The previous item needs to change its
nextpointer. Without this, it’ll keep pointing to freed memory. - Logic for updating
root. This only needs to happen if we freeroot - Communicating possible change in
root. If we remove the root (aka head) item from the list, this needs to be communicated to the caller. I’ve done this by returning the (possibly updated) value ofrootinstead ofNULL