0
votes

Suppose I were to create N number of threads and I would be passing a different string into each thread.

Pseudocode:

for (i = 0; i < N; i++) {
   strncpy(arg.str, some_new_str, sizeof(arg.str));
   pthread_create(&threads[i],NULL,somefunc, (void *) &arg);
}

Would the string pointed to by arg in each thread change? Say for the first thread created, some_new_str is "hello" and for the second, it is "bye". Later when I print the string in thread 1, would the string be changed to "bye" instead of "hello"?

EDIT: So then I should create a new arg struct for each thread?

6
You're not passing different strings to each thread. You're pointing the same pointer to the same object to each thread. - David Schwartz
Think about it this way: How would the system even know how to copy the argument? - Kevin

6 Answers

1
votes

This implementation is not safe. The last argument may change without you noticing it, because pthread_create doesn't create the thread immediately. It will do it at some point, but your local arg may have already changed by that time.

As an example, try running this code:

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

void* worker(void *arg) {
  int val = *((int*)arg);
  printf("% 5d", val);
  return arg;
}

int main() {
  pthread_t thid;
  pthread_attr_t attr;

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    int n = 200;
    int x = 0;
    for(x = 0; x < n; ++x) {
      pthread_create(&thid, &attr, worker, &x);
    }
  sleep(2);
  printf("\n========\n");
}

and check what happens.

Code by P. Czarnik

0
votes

You can check this simply by printing the address of the argument before thread creation and after(from within the executed thread). If the addresses are the same, then you're only passing a pointer. If they're different, then aside from bugs, the thread creation process is likely copying memory to a different location.

But pthread_create() doesn't only take strings. It can take any void*. So how would it know how large the datatype is that it would need to copy?

0
votes

Assuming "arg" is a structure, and arg.str is an array of character bytes within that structure, you will be overwriting the value of arg.str on each iteration of the loop.
You are passing a pointer to the same structure, arg, for each call to pthread_create(), so each thread will have a copy of the very last string (passed to strncpy() on the very last iteration of your for loop)...which I presume is not the desired behavior.

0
votes
  1. If you are copying different strings over to the same arg structure each time, the threads will all see the string changing because you're passing the same address to each thread.

  2. You are not guaranteeing that the string you copy is NUL terminated:

http://linux.die.net/man/3/strncpy

The strncpy() function is similar, except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.

0
votes

Yes As per the Pseudocode:

    for(i = 0; i < N; i++) {
   strncpy(arg.str, some_new_str, sizeof(arg.str));
   pthread_create(&threads[i],NULL,somefunc, (void *) &arg);
}

While creating thread using pthread_create we are passing address of arg. Since argument passing part of pthread_create works as pass by pointer.

Thus all threads will print whatever the value stored at memory location of arg i.e. &arg. If we store "hello" in arg then all threads will print "hello".

0
votes

Apart from Mr M. noticed:

  1. No, arg structure will not be copied by pthread_create function, because the function simply do not know the size of the argument you gave to it.
  2. And so, yes, you should create different structures to every call to pthread_create.

This perfectly proves my words: http://hawk.guru/pthread_create-variable-copying/