1

When I run the following code it seems like the printout is not right.

void thread_Calc(int *pos) {
  printf("recieved %d\n", *pos);
  sig = -1;

  mandel_Calc(&slices[*pos],maxIterations,&res[(*pos)*slices[*pos].imSteps*slices[*pos].reSteps]);

  counter++;
  array[counter] = *pos;
  sig = *pos;
}


int main(int argc, char *argv[]) {

  while (WinH % nofslices != 0) { nofslices++;}

  slice_height = WinH/nofslices;

  level = 1;

  while (1) {

    for (i=0; i<nofslices; i++){
      array[i] = -1;
    }

    y=0;
    sig = -1;
    counter = -1;
    for(i=0; i<nofslices; i++){ 
      printf("Passing %d\n", i);

      check=pthread_create(&worker[i], NULL, (void*)thread_Calc, (void*)(int *)&i);
      if (check!=0) {
        printf("Error in pthread_create\n");
        return 0;
      }

      while (sig==-1||array[counter]==-1){

      }
    }
  } 
}    

(This is just a part of my code, so assume that every variable is right and has a value).

The result I get is something like:

Passing 1
Passing 2
recieved 2
recieved 2
Passing 3
Passing 4
recieved 4
recieved 4
Passing 5
Passing 6
Passing 7
Passing 8
Passing 9

which seems like I can't always pass the right argument in pthread_create or something.

Peter Brittain
  • 13,489
  • 3
  • 41
  • 57
Υρώ Κ.
  • 23
  • 2

2 Answers2

1

@Andrew is right. You pass a pointer not a value, so as soon as you change "i" in the main thread the value is changed in the parameter received by the created thread. You need to create a copy and pass it to the thread.

See pthread_create : passing an integer as the last argument

Community
  • 1
  • 1
0

In this code:

   for(i=0; i<nofslices; i++){ 
      printf("Passing %d\n", i);

      check=pthread_create(&worker[i], NULL, (void*)thread_Calc, (void*)(int *)&i);

the value of i continues to change after each thread gets started.

You pass the address of i, so when it gets dereferenced in the child thread, it holds whatever value your main thread has put into it at that time.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • To be honest I'm not following you completely. Do you mean that I have to pass another variable as an argument which will have the same value as `i`? Or is there another solution? – Υρώ Κ. Oct 18 '16 at 18:37
  • 1
    @ΥρώΚ. You need to get the *value* of `i` when you call `pthread_create()` to the child thread. By passing the *address* of `i` and then dereferencing it in the child thread, you're getting whatever value `i` has in the main thread when it's dereferenced. The quick, dirty hack is to pass the *value* of `i` as the "pointer": `pthread_create( ... ( void * ) i ):`. Note the *lack* of the address-of `&`. Then in the child thread: `void *thread_Calc( void *arg ) { int i = ( int ) arg; ...}` Technically undefined behavior, but it does what's needed quickly - and most importantly, clearly. – Andrew Henle Oct 18 '16 at 18:44
  • Ooh, I see! I'll try that – Υρώ Κ. Oct 18 '16 at 18:45
  • @ΥρώΚ. Remember - that method is a hack. It works on most platforms, but a proper way is linked in Vicente Sirvent's answer. I just think the hack communicates the intent better - it's more clear, with less code (and it fits in a comment...) – Andrew Henle Oct 18 '16 at 18:49
  • That hack works only when void* is the same size as int. If you go to a 64 bits architecture I think that should not even compile... – Vicente Sirvent Oct 18 '16 at 18:52
  • 1
    @VicenteSirvent Oh, it's definitely playing with fire. But it's usually safe for small non-negative `int` values, such as those seen in a `for`-loop used to start threads as you're not likely going to create 2 billion+ (assuming 32-bit `int`). With an explicit cast, it should compile on just about any platform - it does on Linux with GCC (ask me how I know...) - and although I've never run into one, I can easily imagine a platform where it would fail at run-time. – Andrew Henle Oct 18 '16 at 18:59
  • Anyway, both of you guys really helped me! Thank you very much for your interest. – Υρώ Κ. Oct 19 '16 at 19:17