3

I am attempting to pass an array as an argument to a function in a new thread using pthread_create, is this possible? I have an array of integers and a calculate average method that is called from the create thread method but I cannot seem to pass my array into the method correctly. Here is my code: int nums[];

int average;

int size = 0;


void *calcAvg(int *nums[]);

int main(int argc, char *argv[]){
    /* initialize an array of the integers to be passed */
    nums[argc - 1];
    for(int i = 0; i < argc - 1; i++){
        nums[i] = atoi(argv[i + 1]);
        size++;
    }

    /* Thread Identifier */
    pthread_t avgThread;

    pthread_create(&avgThread, NULL, calcAvg, nums);

    pthread_join(avgThread, NULL);

    printf("average= %d", average);
}

void *calcAvg(int *nums[]){
    int sum;
    for(int i = 0; i < size; i++){
        sum += nums[i];
    }
    average = sum / (size);
    pthread_exit(0);
}
7
  • 2
    Does this even compile? nums in main is not even declared properly, it seems. Commented Feb 25, 2014 at 1:58
  • You should really identify whether you've got a compile-time, link-time or run-time problem. The code shown shouldn't be compiling without warnings; if it is, you need to increase the warnings level on your compilations. And you should fix the warnings; remember, the C compiler probably knows more about C than you do. Commented Feb 25, 2014 at 2:26
  • The function for a thread should have the signature void *thread_function(void *arg) — a function that takes a 'universal pointer' (pointer to void) as an argument and returns a pointer to void. Your calcAvg() function doesn't match that, so the solution by michaeltang fixes that problem. There's no particular reason to use pthread_exit(0); at the end; were it my code, I'd use return 0; — but the net result is the same except that the compiler won't complain about not returning a value from a function that is supposed to do so. Commented Feb 25, 2014 at 3:53
  • Within the function, the cast from void * to int * is legitimate given that the input was originally an int array, which is converted first to an int pointer (a pointer to the first element of the array) and then to a void pointer to match the function prototype. Your declaration using int *nums[] manages to use two levels of pointer where only one is required; you would have done better with int *nums or int nums[] — there are equivalent when used in a function declaration or definition (but only in that context — elsewhere, they are rather different). Commented Feb 25, 2014 at 3:56
  • The residual issue is a matter of style — and thread-safety. You use two global variables, size and average. Given that your main thread goes to sleep while the only child thread is executing, there is no problem. If you had two or more child threads, you would need to worry about whether it was safe to use the variables. Given that size is fixed once the threads start (so they'd only read it), then that would be OK. However, if multiple threads are accessing average, you really need a mutex or something similar to protect it from concurrent access. Commented Feb 25, 2014 at 3:59

3 Answers 3

10

there is lots of problem in your code, i fix some to compile hope it will help

compile: gcc -o main main.c -lpthread

execute: ./main 2 5

output: 3

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

int average;

int size = 0;


void *calcAvg(void *arg);
int main(int argc, char *argv[]){
  /* initialize an array of the integers to be passed */
  int *nums = (int*)malloc((argc - 1)*sizeof(int));
  int i = 1;
  for(i = 1; i < argc ; i++){
    nums[i-1] = atoi(argv[i]);
    size++;
  }

  /* Thread Identifier */
  pthread_t avgThread;

  pthread_create(&avgThread, NULL, calcAvg, (void*)nums);

  pthread_join(avgThread, NULL);
  printf("average = %d \n",average);
  free(nums);

}
void *calcAvg(void *arg){
  int *val_p = (int *) arg;
  int sum = 0;
  int i = 0;
  for( i = 0; i < size; i++){
    sum += val_p[i];
  }
  average = sum / (size);
  pthread_exit(0);
}
Sign up to request clarification or add additional context in comments.

5 Comments

The question is tagged C, not C++, so technically you should be using gcc and not g++ to compile. You should also use either a VLA (as the original code attempted to do) or malloc() or a range check and a static array rather than using new.
Thank you, so you must cast the array to a void type? I am still confused in C what the * does exactly. So you're casting the array to a void type, and the * has something to do with declaring it as a pointer, can you elaborate on that please? Thank you!
and is it best practice to cast things to a void type and then cast them back when passing args?
@justinhenricks , it is required when a function used as callback function of thread, you may consider nums as a pointer of int. it think you should read the meaning and usage of * in book
This is a solution to a particular problem and doesn't answer the question posed. Maybe this helped OP but I don't think this is useful to anyone else in the community. IMHO this answer should be removed or modified.
1

Change the following

void *calcAvg(int *nums[]){
    int sum;
    for(int i = 0; i < size; i++){
        sum += nums[i];
    }
    average = sum / (size);
    pthread_exit(0);
}

to

void *calcAvg(void *arg){
    int *val_p = (int *) arg;
    int sum;
    for(int i = 0; i < size; i++){
        sum += val_p[i];
    }
    average = sum / (size);
    pthread_exit(0);
}

Comments

1

The main issue that 'pthread_create()' takes a void pointer as its last argument. You are trying to pass to it an array of pointers to integers. Issue "man pthread_create" at the terminal to see the argument types you should be passing.

What you really want to do is just pass the of array integers to the thread. In C, array indexing is just notation for pointer arithmetic. Writing nums[i] is equivalint to &nums[0] + i or just nums+i. The last case works because the name of an array in C can be used as a pointer to the first element of the array.

change void *calcAvg(int *nums[]) to void *calcAvg(void* thread_args). Then in 'calcAvg' write int *nums = (int*)thread_args. Now you can use nums in that function just as if you had called calcAvg(nums), which in in essence you have done.

1 Comment

Given a prototype in scope, the compiler will automatically convert the int * to a void * in the call. In fact, that should not provoke a warning from the compiler. What should provoke a warning is passing void (*func)(int *) function pointer to a routine expecting a void (*func)(void *).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.