I know how to pass a function as an argument for another function. But I don't know if the argument of a function passed to pthread can be another function. Is this even possible?
Here is sample code that compiles OK, but doesn't work:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_t idThread;
void aFunction(){
while(1){
fprintf(stderr,"I've been called!\n");
usleep(1000000);
}
}
void * threadFunction(void *argFunc){
// Do here some stuff;
// ...
// Now call the function passed as argument
void (*func)() = argFunc;
}
int thread_creator(void(*f)()){
// I want to use as argument for threadFunction the f function
pthread_create(&idThread, NULL, threadFUnction, (void *)f);
}
int main(){
thread_creator(aFunction);
while(1);
return 0;
}
It can be a function pointer, if you're willing to bend rules a little. Strictly speaking a void * isn't guaranteed to be able to hold a function pointer. Something like this (untested):
void some_fun()
{
/* ... */
}
void thread_fun(void *arg)
{
void (*fun)() = arg;
}
pthread_create(...., (void *) some_fun);
EDIT
In your example, you also need to call the function, via the function pointer. Something like:
void (*func)() = argFunc;
funct(); /* <-- */
Stricly speaking, it is not possible. According to the standard, a pointer to void may just be converted to or from a pointer to an object type. On some architectures, function adresses are larger than object adresses.
C11, § 6.3.2.3 Pointers
A pointer to void may be converted to or from a pointer to any object
type. A pointer to any object type may be converted to a pointer to
void and back again; the result shall compare equal to the original
pointer.
Otherwise, it is a common extension.
C11, § J.5.7 Function pointer casts
A pointer to an object or to void may be cast to a pointer to a
function, allowing data to be invoked as a function (6.5.4).
In your example, you don't call func.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_t idThread;
void aFunction(void)
{
while (1) {
fprintf(stderr, "I've been called!\n");
usleep(1000000);
}
}
void *threadFunction(void *argFunc)
{
void (*func)(void) = argFunc;
func(); /* HERE */
}
int thread_creator(void (*f)(void))
{
pthread_create(&idThread, NULL, threadFUnction, (void *) f);
}
int main(void)
{
thread_creator(aFunction);
while (1);
return 0;
}
To add to the answers already given:
Conceptually, function pointers can be passed around just like any other type of pointer, but - as has been pointed out - a void * is not guaranteed to be large enough to hold a function pointer, only a data pointer.
A workaround for something like the pthread_create callback function is to wrap your desired function pointer in a structure that you use as the user data:
struct threadArg
{
void (*callback)(void);
};
// ...
struct threadArg *threadArg = malloc(sizeof(threadArg));
threadArg->callback = myFunction;
pthread_create(&idThread, NULL, threadFunction, (void *) threadArg);
There is no need for dubious casts involving function pointers. The argument to the thread can be a pointer to a struct which can contain anything.
#include <pthread.h>
struct arg {
void (*func)(void);
int other_stuff;
};
void function(void)
{
}
void *thread_function(void *arg)
{
struct arg *a1 = arg;
a1->func();
return NULL;
}
int main(void)
{
pthread_t tid;
struct arg arg = {.func = function};
pthread_create(&tid, NULL, thread_function, &arg);
.
.
.
}
Related
Say that I have a pointer to function theFunc. theFunc takes along a pointer that can point to any function with the same parameter list as theFunc, so the function called can set the passed pointer to NULL or a different function.
Using it would look like this:
while (funcPtr != NULL)
{
funcPtr(&funcPtr);
}
Would defining this be impossible?
Yes, it's doable.
The simple way:
void (*fptr_t)(void*);
The function pointer is data, even though it point to non-data. Therefore a pointer to function pointer can be converted to void* without relying on compiler extensions.
This solution lacks type safety. However, it can be improved.
Currently, it is possible to declare a function taking unspecified number of parameters. It allows to form an incomplete function type. For example:
int foo();
declares a function that returns int and takes unspecified parameters. To have a function taking no parameters use int foo(void).
This allows to declare a function taking a pointer to pointer to incomplete function type:
int foo(int (**)());
// call
int (*fptr)(int (**)()) = foo;
fptr(&fptr);
As mentioned in other answers typedef-ing function types makes the code cleaner.
typedef int foo_aux_f();
typedef int foo_f(foo_aux_f**);
foo_f *fptr = &foo;
fptr(&fptr);
It is possible to improve type safety by nesting the declaration of function types deeper and deeper.
typedef int foo_aux0_f();
typedef int foo_aux1_f(foo_aux0_f**);
typedef int foo_aux2_f(foo_aux1_f**);
typedef int foo_aux3_f(foo_aux2_f**);
typedef int foo_f(foo_aux3_f**);
foo_f fptr = &foo;
fptr(&fptr);
The perfect recursive type would be reached with infinite chain of declaration but in practice 2-3 levels are sufficient.
With some abuse of the syntax of typedef keyword it is possible to squeeze the declaration of this type:
typedef int foo_aux0_f(),
foo_aux1_f(foo_aux0_f**),
foo_aux2_f(foo_aux1_f**),
foo_aux3_f(foo_aux2_f**),
foo_f(foo_aux3_f**);
Unfortunately ... or fortunately, this trick will likely not work in upcoming C23 because the old function declarations without prototypes are planned to be removed from the language making () mean no arguments rather then unspecified number of argument.
Yes, you can pass pointer to pointer to function. The syntax is much easier if you use typedefs.
typedef void somefunc(void);
void func1(void)
{
printf("Func1\r");
}
void func2(void)
{
printf("Func2\r");
}
void swapfunction(somefunc **ptr)
{
if(*ptr == func1) *ptr = func2;
else *ptr = func1;
}
int main(void)
{
somefunc *ptr = NULL;
swapfunction(&ptr);
ptr();
swapfunction(&ptr);
ptr();
}
You can also use function return value:
typedef void somefunc(void);
void func1(void)
{
printf("Func1\r");
}
void func2(void)
{
printf("Func2\r");
}
somefunc *swapfunction(somefunc *ptr)
{
if(!ptr) return func1;
else if (ptr == func1) return func2;
else return NULL;
}
int main(void)
{
somefunc *ptr = NULL;
while(ptr = swapfunction(ptr))
{
ptr();
}
}
Ref your github comment, suggest you use a structure instead of type casting pointers to function pointers, etc. It's not exactly what you are requesting, but kind of.
The code will then look like:
#include <stdio.h>
struct funcArgStruct
{
void (*state)(struct funcArgStruct *);
// int extra_data; // optional
};
typedef struct funcArgStruct funcArg;
void start (funcArg *ptr);
void task1 (funcArg *ptr);
void stop (funcArg *ptr);
/* Implementation of an fsm. */
int main()
{
funcArg ptr_, *ptr = &ptr_;
ptr->state = start;
// ptr->extra_data = 0; // optional
while (ptr->state != NULL)
{
ptr->state(ptr);
}
return 0;
}
void start (funcArg *ptr)
{
ptr->state = task1;
}
void stop (funcArg *ptr)
{
ptr->state = NULL;
}
void task1 (funcArg *ptr)
{
ptr->state = stop;
}
This sort of works:
#include <stdio.h>
void *a(void)
{
printf("Calling a()\n");
return NULL;
}
void *b(void)
{
printf("Calling b()\n");
return a;
}
void *c(void)
{
printf("Calling c()\n");
return b;
}
int main(void)
{
void *(*funcPtr)(void) = &c;
while (funcPtr) {
funcPtr = funcPtr();
}
}
I don't really see good uses, especially in passing the pointer to the function itself as an argument (which I why I omitted it) but whatever floats your boat. You can of course replace the arguments to whatever you need.
You could add a typedef to help out a bit with a type:
typedef void *(*myfunc)(void);
Then you could do the following:
myfunc funcPtr = &c;
// instead of: void *(*funcPtr)(void) = &c;
I don't think any of this is particularly elegant, but it should work.
Note that it doesn't matter if you assign c or &c to myfunc, or whether you return a or &a from one of the functions.
#include <stdio.h>
#include <stdlib.h>
// Thread Declarations
#include <pthread.h>
pthread_t monitor_thread;
void *Get_Monitor_Data(void *BM_params);
// this is my struct ///
typedef struct
{
HCORE BM_cores[0];
int total_cores;
} BM_PARAMS;
BM_PARAMS BM_Dat;
int Start_monitor(void)
{
int RETVAL=0;
RETVAL = pthread_create(&monitor_thread, NULL, Get_Monitor_Data,(void*)BM_Dat);
if(RETVAL !=0)
{
printf("Error Starting Thread \n");
}
return 0;
}
void *Get_Monitor_Data (void *BM_Dat) // Bus Monitor Thread
{
BM_PARAMS*monitor_params;
int no_of_cores=0;
monitor_params = (BM_PARAMS *) BM_Dat;
BTICard_CardReset(*monitor_params->BM_cores);// reset card if required
return 0;
}
The pthread create portion is giving error of "cannot convert to a pointer type"
is there anything wrong which i am doing?
i need to pass a structure to the P thread function as argument, how can i do that?
You're trying to cast BM_Dat which has structure type to a void *. A struct cannot be converted to a pointer. You can however pass the address of BM_Dat:
RETVAL = pthread_create(&monitor_thread, NULL, Get_Monitor_Data, &BM_Dat);
A BM_PARAMS * can be converted to a void * (implicitly in fact), and in fact your thread function converts the parameter to this type.
this is the right use of pthread_create with no warning:
#include <pthread.h>
#include <stdio.h>
void *check(void *temp) {
int* i = (int *)temp;
printf("%d\n", *i);
}
int main(void) {
pthread_t check_thread;
int i = 1;
pthread_create(&check_thread, NULL, check , (void *)&i);
pthread_join(check_thread, NULL);
return 0;
}
but the following code can also run well, just change void *check to void check:
#include <pthread.h>
#include <stdio.h>
void check(void *temp) {
int* i = (int *)temp;
printf("%d\n", *i);
}
int main(void) {
pthread_t check_thread;
int i = 1;
pthread_create(&check_thread, NULL, check, (void *)&i);
pthread_join(check_thread, NULL);
return 0;
}
if i change check to &check, it can also run well
#include <pthread.h>
#include <stdio.h>
void check(void *temp) {
int* i = (int *)temp;
printf("%d\n", *i);
}
int main(void) {
pthread_t check_thread;
int i = 1;
pthread_create(&check_thread, NULL, &check, (void *)&i);
pthread_join(check_thread, NULL);
return 0;
}
i see the thrid argument of pthread_create is: void *(*start_routine) (void *)
can someone tell me what does it mean?
Per the POSIX standard for pthread_create():
SYNOPSIS
#include <pthread.h>
int pthread_create(pthread_t *restrict thread,
const pthread_attr_t *restrict attr,
void *(*start_routine)(void*), void *restrict arg);
That means that the third argument to pthread_create() must be a function pointer of the form void *(*start_routine)(void*). The function pointer passed must refer to a function
declared and defined as
void *start_routine( void *arg )
{
void *ptr = ...;
...
return( ptr );
}
Period. End of discussion. Full stop.
You are invoking undefined behavior by not passing a function of the type void *(*start_routine) (void *) as the third argument to pthread_create().
Per J.2 Undefined behavior, paragraph 1 of the C standard:
The behavior is undefined in the following circumstances:
...
A pointer is used to call a function whose type is not compatible with the referenced type.
"Works with no observed issue" is covered by "undefined behavior". "Program crashes" is also covered.
The deal of the C standard is to write portable code, that could run on any conforming platform. The fact that this runs on your platform without visible errors, does not mean that it would on other platforms. Reasons for failure could e.g be that pthread_join could try to access a hardware register with the return value.
It is nothing but a function pointer. Lets break it down.
void *(*start_routine) (void *)
void* -> return type of function
start_routine -> function pointer name
void* -> argument type
the address of the function you pass will be assigned to function pointer start_routine and start_routine will be invoked as new thread from kernel.
I wanna call multiple functions and deal with their return values (using pthread_join) in main(), but they are all int functions with multiple non-void arguments, and the definition of pthread_create is:
int pthread_create(pthread_t * thread,
const pthread_attr_t * attr,
void * (*start_routine)(void *),
void *arg);
all examples of the start_routine I found in the internet are type of void * with type of single void * argument, is it possible to call int functions with multiple non-void type arguments in pthread_create?
You want to wrap the int function into a function of the required type.
So assuming you want to return an int you might do it like this:
(The example assume C99 and leaves out relevant error checking for the sake of readebility.)
#include <inttypes.h> /* for intptr_t */
#include <stdio.h>
#include <pthread.h>
struct S
{
int x;
int y;
};
int sum(int x, int y)
{
return x + y;
}
void * thread_function(void * pv)
{
struct S * ps = pv;
pthread_exit((void *) (intptr_t) sum(ps->x, ps->y));
}
int main(void)
{
struct S s = {41, 1};
pthread_t pt;
pthread_create(&pt, NULL, thread_function, &s);
void * pv;
pthread_join(pt, &pv);
int z = (intptr_t) pv;
printf("%d + %d = %d\n", s.x, s.y, z);
}
This prints:
41 + 1 = 42
The casting to and from intptr_t is necessary to assure the misuse of a pointer value as an integer does not violate the C-Standard.
If you look at the manual page you will see that the function argument is
void *(*start_routine) (void *).
You cannot pass a different type of function to start routine.
You can use (void *) to pass an argument to start_routine.
You can cast the pThread pointer to some type compatible with integer. Better solution is to put the entire functionality in a wrapper function. Please refer to the below link:
C++, create a pthread for a function with a return type?
Let's see if I understood the question.
You want to call a function with a signature like
int myfunct(int a, int b, int c)
then define a struct like this
struct my_funct_param_t
{
int a ;
int b ;
int c ;
} ;
and a wrapper to use as start routine
void *myfunct1(void *arg)
{
my_funct_param_t *arg1 = (my_funct_param_t *)arg ;
myfunct(arg1->a, arg1->b, arg1->c) ;
....
}
The code that starts the thread must create the my_funct_patam_t object and fill in accordingly. Beware of this object lifetime....
The solution consists of two parts, one is a static library that receives instances of struct from the user of the library. Library doesn't know what will be the type of structs, all it knows there will be two function pointers to it with a specific name.
Library Code
pre-compiled library has no way of knowing types of user structs, hence receiving via void*
void save(void *data) {
// library will save/cache user's object
data->registered(); // if register successful
}
void remove(void *data) {
// library will remove the object from memory
data->remove(); // if removed successful
}
User of the Library Code
struct Temp { // random order of fields
void (*custom1)();
void (*registered)();
void (*custom2)();
void (*remove)();
void (*custom3)();
}
void reg() {
printf("registered");
}
void rem() {
printf("removed");
}
void custom1() {}
void custom2() {}
void custom3() {}
var temp = malloc(struct Temp, sizeof(struct Temp));
temp->registered = reg;
temp->remove = rem;
temp->custom1 = custom1; // some custom functions
temp->custom2 = custom2;
temp->custom3 = custom3;
// calling library code
save(temp);
remove(temp);
Q. Is there a way for the Library to know how to iterate and go through member fields and see if there's a pointer to such function and call it available.
Is there a way for the Library to know how to iterate and go through member fields and see if there's a pointer to such function and call it available.
No there is not.
Your best bet is to create a structure in the library that has these members, and pass that structure instead of void*.
As #immibis said, there is no way for this to work (i.e. no way for the compiler to justify compiling such code) if the compiler does not know what the types of the data being passed to the function are.
Since you wanted to pass the objects along to the library without storing information about the type of each object in the library, you can fake polymorphism in C, by doing the following:
callback.h
#ifndef _CALLBACK_H_
#define _CALLBACK_H_
typedef struct {
void (*registered)();
void (*removed)();
} ICallback;
#endif _CALLBACK_H_
pre_comp.h
#ifndef _PRE_COMP_H_
#define _PRE_COMP_H_
#include "callback.h"
void save(ICallback* data);
void remove(ICallback* data);
#endif /* _PRE_COMP_H_ */
precomp.c
#include <stdlib.h> /* NULL */
#include "callback.h"
#include "pre_comp.h"
void save(ICallback *data) {
if (NULL != data && NULL != data->registered) {
data->registered(); // if register successful
}
}
void remove(ICallback *data) {
if (NULL != data && NULL != data->removed) {
data->removed(); // if removed successful
}
}
main.c
#include <stdio.h>
#include "pre_comp.h"
#include "callback.h"
struct Temp {
ICallback base; // has to be defined first for this to work
void (*custom1)();
void (*custom2)();
void (*custom3)();
};
// calling library code
void reg() {
puts("registered");
}
void rem() {
puts("removed");
}
int main() {
struct Temp data = {{reg, rem}};
save((ICallback*)&data);
remove((ICallback*)&data);
}
compiling
gcc pre_comp.c main.c
output
registered
removed
If the library has 0 information about the possible struct types, then you
cannot do it. The library has to get somehow the information or the offsets.
The only way I can think of is:
All register member have the same prototype
Pass the offset to the function.
I created an example of this
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
// function that does not know anything about any struct
void reg(void *data, size_t offset)
{
uintptr_t *p = (uintptr_t*) (((char*) data) + offset);
void (*reg)() = (void(*)()) *p;
reg();
}
struct A {
int c;
void (*reg)();
};
struct B {
int b;
int c;
void (*reg)();
};
void reg_a()
{
printf("reg of A\n");
}
void reg_b()
{
printf("reg of B\n");
}
int main(void)
{
struct A a;
struct B b;
a.reg = reg_a;
b.reg = reg_b;
reg(&a, offsetof(struct A, reg));
reg(&b, offsetof(struct B, reg));
return 0;
}
This prints:
$ ./c
reg of A
reg of B
I run it with valgrind and I did not get any errors nor warnings. I'm not sure if
this violates somehow strict aliasing rules or yields undefined behaviour
because of the uintptr_t* conversions, but at least it seems to work.
I think however, the more cleaner solution is to rewrite the register (btw. register
is a keyword in C, you cannot use that for a function name) function to
accept a function pointer and possible parameters, something like this:
#include <stdio.h>
#include <stdarg.h>
void reg(void (*func)(va_list), int dummy, ...)
{
if(func == NULL)
return;
va_list ap;
va_start(ap, dummy);
func(ap);
va_end(ap);
}
void reg1(int a, int b)
{
printf("reg1, a=%d, b=%d\n", a, b);
}
void vreg1(va_list ap)
{
int a = va_arg(ap, int);
int b = va_arg(ap, int);
reg1(a, b);
}
void reg2(const char *text)
{
printf("reg2, %s\n", text);
}
void vreg2(va_list ap)
{
const char *text = va_arg(ap, const char*);
reg2(text);
}
int main(void)
{
reg(vreg1, 0, 3, 4);
reg(vreg2, 0, "Hello world");
return 0;
}
This has the output:
reg1, a=3, b=4
reg2, Hello world
Note that reg has a dummy parameter. I do that because the man page of
stdarg says:
man stdarg
va_start():
[...]
Because the address of this argument may be used in the va_start() macro,
it should not be declared as a register variable, or as a
function or an array type.
You can take an approach similar to qsort and pass function pointers in addition to a void pointer to the structure.
Here is the function prototype for qsort, which is a function that can be used to sort arrays of any type:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
It takes a function pointer that performs the comparison because without it qsort wouldn't know how to compare two objects.
This can be applied to your task with a function prototype like this:
int DoFoo(void *thing, void (*register)(void *), void (*remove)(void *))
This function takes a void pointer to your struct and then two functions that it can call when it needs to register or remove that struct. Having the functions be members of the struct is not required and I generally do not recommend it. I recommend reading up on qsort because it is does something similar to what you are trying to do.