Reputation: 11
This might be a bit specific, but I want to know, how to return a ... let's see the code first actually.
void *atomic_op(void * (*f)(),void* ret) // Using a function pointer to encapsulate the procedure in between locks
{
pthread_mutex_lock(&mut1);
ret = f;
pthread_mutex_unlock(&mut1);
}
I want to be able to get the return value of f
and store it to ret
using void pointers for more general use.
My IDE informs me that argument ret
is not accessed outside the scope of this function, but later down my code there is
char* temp;
while (1)
{
atomic_op(readBuffer(shared_array),temp);
if (*temp == 0)
{
break;
}
atomic_op(printOutBuffer(shared_array),NULL);
}
When running the whole thing, the IDE comes our right (of course) but I cannot understand why.
The whole thing is an attempt on monitors, with 2 threads sharing an array in a consumer producer relationship (just experimenting) and I stumbled across this which I found really weird!
Can someone explain what happens here?
The whole thing is here https://controlc.com/2af8f50c
Link with pthread
Upvotes: 1
Views: 314
Reputation: 223872
First off, this doesn't actually call the function:
ret = f;
It just takes the function pointer and assigns it to ret
. To call the function you want f()
.
Also, because parameters in C are passed by value, changes to the parameter ret
aren't reflected in the calling function. That fact that ret
is a pointer type doesn't matter.
If you want a function to update a pointer value it needs to take a pointer to a pointer. That pointer-to-pointer parameter must then be dereferenced to update the pointer variable in the calling function.
Making these fixes, your function would look like this:
void *atomic_op(void * (*f)(),void **ret)
{
pthread_mutex_lock(&mut1);
if (ret) {
*ret = f();
}
pthread_mutex_unlock(&mut1);
}
And you would call it like this:
char *tmp;
void *tmp2;
atomic_op(readBuffer(shared_array),&tmp2);
tmp = tmp2;
Here the extra void *
variable is required because a char **
is not guaranteed to be safely converted to a void **
.
There's still one thing we haven't addressed, and that's that the function is defined to return a void *
but doesn't actually return anything. This is OK for your program since you're not attempting to access the return value, but still it's a bad code smell.
It would be better to take the return value of f
and make that the return value of atomic_op
and get rid of the second parameter. This also means you don't need a second variable in the calling function.
So now we have:
void *atomic_op(void * (*f)())
{
void *ret;
pthread_mutex_lock(&mut1);
ret = f();
pthread_mutex_unlock(&mut1);
return ret;
}
Which would be called like this:
char *tmp;
tmp = atomic_op(readBuffer(shared_array));
All this is assuming that readBuffer
and printOutBuffer
return function pointers. If they don't, you need to pass just the name of the function and the function's parameters to atomic_op
, and the type of f
would need to match the type of readBuffer
and printOutBuffer
. That would give you:
void *atomic_op(void *(*f)(void *), void *param)
{
void *ret;
pthread_mutex_lock(&mut1);
ret = f(param);
pthread_mutex_unlock(&mut1);
return ret;
}
Which is called like this:
char *tmp;
tmp = atomic_op(readBuffer, shared_array);
Upvotes: 2