I want to make a copy of a struct, then pass it into pthread, and finaly free it inside the pthread thread. But i can't fingure this out, it's simply to far beyond me at this point and i can't find any tutorial about passing a cloned struct, and freeing them inside thread. Pseudo code below:
typedef struct unit_t { int id; char value[20]; char pid[20]; char id[100]; int type; }
pthread_t th;
void* myThread(void *arg){
how do i print a struct value and free arg in here?
free(arg);
}
void someFunction(*unit){
//create a local copy of struct
unit_t *tmp = malloc(sizeof(struct unit_t));
//clone initial *unit
*tmp = *unit;
//spawn thread
if(pthread_create(&th, NULL, &myThread, &tmp) != 0) {
bwlog("failed to create thread");
//free tmp if thread failed
free(tmp);
}else{
pthread_detach(th);
}
}
CodePudding user response:
A void *
can be implicitly converted to any pointer type.
Note, however, that passing &tmp
(the address of an object with automatic storage duration) is dangerous in your code, since you do not ensure that the lifetime of tmp
matches the lifetime of the created thread.
In other words, &tmp
points to a local variable in someFunction
. someFunction
may return before the thread finishes its execution, in which case arg
will be a dangling pointer.
You want to pass the value of tmp
(the address of an object with allocated storage duration).
Note also that the address of a function (&myThread
) has same value as the function itself (myThread
). The address-of operator is superfluous here.
A cursory example, with no error handling, that continuously spawns threads that are passed dynamically allocated memory.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
struct foo {
int a;
int b;
};
void *thread_runner(void *arg) {
struct foo *data = arg;
printf("%d %d = %d\n", data->a, data->b, data->a data->b);
free(data);
return NULL;
}
int main(void) {
srand((unsigned) time(NULL));
while (1) {
pthread_t id;
struct foo *data = malloc(sizeof *data);
data->a = rand() / 2;
data->b = rand() / 2;
pthread_create(&id, NULL, thread_runner, data);
pthread_detach(id);
sleep(3);
}
}
Care must be taken with "cloning" a structure the way you have. This would be considered a shallow copy, performing a byte for byte copy of the structure.
While this is fine for the structure you have defined, a problem arises when a structure contains a pointer (or nested pointers). A shallow copy of such a structure would result in both structures holding the same pointer to a single object.
Like before, when threads are involved, the pointed-to-object's lifetime may not match the lifetime of a thread, or if the pointer is to dynamically allocated memory, the (difficult) question to answer becomes Where and when is the object freed?
A deep copy may be needed.
CodePudding user response:
You did say your post is pseudo code, but it has a few problems.
- You forgot to actually
typedef
, and you have two fields with the same name:
typedef struct unit_t
{
int id;
char value[20];
char pid[20];
char strId[100]; // this cannot be named id, that already exists
int type;
} unit_t; // need to add the new name at the end, and end it with a semicolon
- Always check the return value of
malloc
unit_t *tmp = malloc(sizeof(struct unit_t));
if (tmp == NULL) // handle error
- No need to pass the address of
tmp
, it's already a pointer.
pthread_create(&th, NULL, &myThread, tmp)
- In your thread function, you need to cast the argument back to the appropriate type, do what you want with it, then you can
free
it. You should also exit the function appropriately:
void* myThread(void *arg){
unit_t* myDupeUnit = (unit_t*)arg;
printf("id = %d\n", myDupeUnit->id);
printf("strId = %s\n", myDupeUnit->strId);
free(myDupeUnit);
pthread_exit(NULL);
}
I don't know the larger scope of what you're doing, but I replaced pthread_detach
with pthread_join
just to make sure everything executes before the process terminates. You can find a working demonstration here.