I made a simple program in pthreads that passed multiple parameters to the called function via a struct. Consider these two programs:
Program 1 :
#include <pthread.h>
#include <stdio.h>
#include <malloc.h>
struct args{
long long val1;
int val2;
};
void *hello(void* threadid){
struct args *tid;
tid=(struct args*)threadid;
printf("thread %lld\n",tid->val1);
pthread_exit(NULL);
}
int main(){
pthread_t threads[20];
int i;
for(i=0;i<20;i++){
// ***** specific memory given to the struct *****
struct args* a1=(struct args*)malloc(sizeof(struct args));
a1->val1=i;
a1->val2=i+1;
int ret=pthread_create(&threads[i],NULL,hello,(void*)a1);
if(ret){
printf("error code %d for %d\n",ret,i);
}
}
pthread_exit(NULL);
}
which prints output as expected, some permutation of 0..19
On the other hand, consider
Program p2
#include <pthread.h>
#include <stdio.h>
struct args{
long long val1;
int val2;
};
void *hello(void* threadid){
struct args *tid;
tid=(struct args*)threadid;
printf("thread %lld\n",tid->val1);
pthread_exit(NULL);
}
int main(){
pthread_t threads[20];
int i;
for(i=0;i<20;i++){
// ***** struct made like normal declarations *****
struct args a1;
a1.val1=i;
a1.val2=i+1;
int ret=pthread_create(&threads[i],NULL,hello,(void*)&a1);
if(ret){
printf("error code %d for %d\n",ret,i);
}
}
pthread_exit(NULL);
}
This program has repeating and incomplete entries, like
thread 3
thread 5
thread 3
thread 4
thread 3
thread 6
thread 7
thread 8
thread 9
thread 10
thread 11
thread 12
thread 13
thread 15
thread 15
thread 16
thread 17
thread 18
thread 19
thread 19
Why is instantiation of struct directly causing overlap of this kind? Shouldn’t C provide a new memory block for each time in the loop?
In your second example,
a1is declared with automatic-storage duration in aforloop. This means that at the end of every iteration, that storage location may then be re-used for the next iteration. Therefore:…you may be passing an address (
&a1) to a memory location that will be modified in the subsequent iteration.mallocon the other hand, will allocate a pointer to a different memory location at every iteration.Since there’s no guarantee whether or not the thread will execute before or after the next iteration begins, you may actually get different results each time you run the above code.
Furthermore, using
mallocwithout storing the pointers anywhere or free them in the thread will result in memory being leaked. Your struct may also go out of scope before all your threads finish, the result being them accessing a dangling pointer. Lastly, since you’re not joining any of your threads, there’s no telling how many will actually execute completely before the program exits.Welcome to the fantastic world of multi-threading.