How to pass an int as “void *” to thread start fun

2019-07-13 12:02发布

I originally had a global variable for my fibonacci variable array, but found out that is not allowed. I need to do elementary multithreading and handle race conditions, but I can't get past feeding an int as a void argument in pthread create. I've tried using a constant pointer with no luck. For some strange reason the void* gets past the first boolean test but not the else if:

  $ gcc -o fibonacci fibonacci.c
    fibonacci.c:22:16: warning: comparison between pointer and integer ('void *' and 'int')
      else if (arg == 1)
               ~~~ ^  ~
    1 warning generated.

My code is a mess and I am getting really confused because I have rewritten it so many times. If I cast all the args in my thread run function as ints I get a segmentation fault 11, which makes sense. All attempts at passing the i index by address and dereferencing it have failed, as it is a void and can't be used as an int. Can you suggest something else?

#include<stdio.h> //for printf
#include<stdlib.h>  //for malloc
#include<pthread.h> //for threading

#define SIZE 25 //number of fibonaccis to be computed
int *fibResults;  //array to store fibonacci results

void *run(void *arg)  //executes and exits each thread
{
  if (arg == 0)
  {
    fibResults[(int)arg] = 0;
    printf("The fibonacci of %d= %d\n", (int)arg, fibResults[(int)arg]);    
    pthread_exit(0); 
 }

  else if (arg == 1)
  {
    fibResults[(int)arg] = 1;
    printf("The fibonacci of %d= %d\n", (int)arg, fibResults[(int)arg]);   
    pthread_exit(0);  
  }
  else
  {
    fibResults[(int)arg] = fibResults[(int)arg -1] + fibResults[(int)arg -2];
    printf("The fibonacci of %d= %d\n", (int)arg, fibResults[(int)arg]);
    pthread_exit(0);
  }
}

//main function that drives the program.
int main()
{
  pthread_attr_t a;
  fibResults = (int*)malloc (SIZE * sizeof(int));
  pthread_attr_init(&a);  

  for (int i = 0; i < SIZE; i++)
  {
    pthread_t thread;
    pthread_create(&thread, &a, run,(void*) &i);
    printf("Thread[%d] created\t", i); 
    fflush(stdout);
    pthread_join(thread, NULL);
    printf("Thread[%d] joined & exited\t", i); 
  }
  return 0;
}

3条回答
干净又极端
2楼-- · 2019-07-13 12:16

You don't need the cast in the call to pthread_create() — the conversion to void * is automatic.

In the thread function, you could use

int i = *(int *)arg;

However, you've now got a synchronization problem; all the threads are using the same (pointer to the same) integer variable, and you can't predict which value they're going to see because of scheduling issues. The per-thread data needs to be 'per thread'.

So, there are various ways around that. In this context, I'd probably use

#include <stdint.h>

and in main():

    pthread_create(&thread, &a, run, (void*)(uintptr_t)i);

and then in the thread function:

int i = (uintptr_t)arg;

Now the casts — the double cast even — is necessary. The cast to uintptr_t ensures the integer value is big enough to hold a pointer; the cast to void * is needed because there isn't an implicit cast from any integer type to void *. This ensures each thread function invocation has a different value. Sharing a pointer to an int means that everything is uncontrolled.

查看更多
【Aperson】
3楼-- · 2019-07-13 12:36

In the run() function you should do:

void *run(void *ptrarg)  //executes and exits each thread
{
  int arg = *((int *)ptrarg);
  if (arg == 0)
  ....
  ....

and in rest of the run(), you don't need to cast the arg. Replace (int)arg with arg.

EDIT:
The way you are passing the argument to fun() while creating threads may cause race condition because all threads will be using same pointer. Check the @Jonathan's answer to avoid this problem.

查看更多
劫难
4楼-- · 2019-07-13 12:40

@efuddy. Instead of (int)arg you should use (int *)arg to properly cast the **void pointer* void *arg

查看更多
登录 后发表回答