I'm using bog-standard x86-64 Ubuntu gcc, and obviously there are no compile problems since I can get a segfault.
I'm trying to create a pthread that invokes a function that takes another function based on some previously determined condition. That is, I'm trying to modify the function invoked in the thread by partially applying its input function.
Code
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <stdlib.h>
#include <stdint.h>
void * (*foo)(void*);
void * (*bar(void (*outputFun)(uint8_t a, short unsigned int b)))(void *);
void baz(u_int8_t a, short unsigned int b) {
printf("a - b is %d - %d\n", a, b);
}
void bay(u_int8_t a, short unsigned int b) {
printf("b - a is %d - %d\n", b, a);
}
int main() {
srand(time(NULL));
unsigned int random = 1 rand() % 2;
printf("Our random number is: %d\n", random);
foo = bar(random > 1 ? *baz : *bay);
pthread_t thread;
pthread_create(&thread, NULL, foo , NULL);
// DO SOME STUFF
pthread_join(thread, NULL);
}
void * (*bar(void (*outputFun)(uint8_t a, short unsigned int b)))(void *) {
// DO OTHER STUFF
outputFun(1, 2);
return NULL;
}
valgrind Error Output
Our random number is: 2
a - b is 1 - 2
--15699-- REDIR: 0x4914b10 (libc.so.6:calloc) redirected to 0x483dce0 (calloc)
==15699== Thread 2:
==15699== Jump to the invalid address stated on the next line
==15699== at 0x0: ???
==15699== by 0x485E608: start_thread (pthread_create.c:477)
==15699== by 0x4998132: clone (clone.S:95)
==15699== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==15699==
==15699==
==15699== Process terminating with default action of signal 11 (SIGSEGV)
==15699== Bad permissions for mapped region at address 0x0
==15699== at 0x0: ???
==15699== by 0x485E608: start_thread (pthread_create.c:477)
==15699== by 0x4998132: clone (clone.S:95)
--15699-- REDIR: 0x49136d0 (libc.so.6:free) redirected to 0x483c9d0 (free)
==15699==
==15699== HEAP SUMMARY:
==15699== in use at exit: 272 bytes in 1 blocks
==15699== total heap usage: 2 allocs, 1 frees, 1,296 bytes allocated
==15699==
==15699== Searching for pointers to 1 not-freed blocks
==15699== Checked 8,476,712 bytes
==15699==
==15699== LEAK SUMMARY:
==15699== definitely lost: 0 bytes in 0 blocks
==15699== indirectly lost: 0 bytes in 0 blocks
==15699== possibly lost: 272 bytes in 1 blocks
==15699== still reachable: 0 bytes in 0 blocks
==15699== suppressed: 0 bytes in 0 blocks
==15699== Rerun with --leak-check=full to see details of leaked memory
==15699==
==15699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==15699==
==15699== 1 errors in context 1 of 1:
==15699== Jump to the invalid address stated on the next line
==15699== at 0x0: ???
==15699== by 0x485E608: start_thread (pthread_create.c:477)
==15699== by 0x4998132: clone (clone.S:95)
==15699== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==15699==
==15699== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
Fwiw, I'm a Java developer. So, I need all the help I can get, and it will be greatly appreciated. Thanks.
EDIT Apparently, I can't make C bend to my will.
CodePudding user response:
You can do what you want, just not exactly the way you want.
Some issues:
- With
foo = bar(random > 1 ? *baz : *bay);
you're trying to create a "closure" which C doesn't have - You can't call a function with (e.g.
*baz
). You'd needbaz()
- But, I think you just want the address of the function which is (e.g.)
baz
For threads, the last argument to pthread_create
is a pointer that gets passed to the thread function. You can create a struct
that has all the information/arguments you require. You pass the address of that struct and the thread function can access it.
Here is a refactoring to do the equivalent in a more standard way:
#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <stdlib.h>
#include <stdint.h>
typedef void (*outputFun) (uint8_t a, short unsigned int b);
typedef struct {
u_int8_t a;
unsigned int b;
outputFun foo;
} args_t;
void
baz(u_int8_t a, short unsigned int b)
{
printf("a - b is %d - %d\n", a, b);
}
void
bay(u_int8_t a, short unsigned int b)
{
printf("b - a is %d - %d\n", b, a);
}
void *
bar(void *vp)
{
args_t *arg = vp;
// DO OTHER STUFF
arg->foo(arg->a,arg->b);
return NULL;
}
int
main(void)
{
srand(time(NULL));
unsigned int random = 1 rand() % 2;
printf("Our random number is: %d\n", random);
args_t arg;
arg.foo = (random > 1) ? baz : bay;
arg.a = 23;
arg.b = 37;
pthread_t thread;
pthread_create(&thread, NULL, bar, &arg);
// DO SOME STUFF
pthread_join(thread, NULL);
return 0;
}