2

My case is similar to another Question.

I would like to pass a function as argument and an integer value. Testing the case with a simplfied construction:

void print (int x, int y) 
{ cout << "x = " << x << ", y = " << y << endl; }

void *interrupt (struct arg_struct args);

struct arg_struct { 
    void (*func)(int,int);          // Argument 1
    int a;                          // Argument 2
    int b;                          // Argument 3
};  

int _tmain(int argc, _TCHAR* argv[]){ 

    int a = 1700, b = 1000;

    struct arg_struct arguments;

    arguments.func = print;
    arguments.a = a;
    arguments.b = b;

    (*interrupt)(arguments);

    cin.get(); return 0;
}


void *interrupt (struct arg_struct args) {

    void (*func) (int,int) ;

    func =  args.func;
    int x = args.a;
    int y = args.b;

    (*func)(x,y);

    return 0;           // Erfordert Rückgabewert
}

So now I want to create a thread to execute this passed function.

void *InThread_func(struct arg_struct *);   // Prototype                        

struct arg_struct { 
    void (*func)(int);          // Argument 1
    int IntNumber;              // Argument 2
};

int InThread(void (*func)(int), int IntNumber){
    
    struct arg_struct arguments;
    
    arguments.func   = func;
    arguments.IntNumber = IntNumber;

    // Initialize handler
    pthread_t InThread_thread;
    
    // Create thread
    pthread_create(&InThread_thread,NULL,&InThread_func,(void*) &arguments);
    
    pthread_join(InThread_func,NULL);

    return(errno);
}

Using

g++-4.6 -o test test.cpp

the compiler says

invalid conversion from void* (*)(arg_struct*) to void * (*)(void*)

referring to the last argument of pthread_create.

Why is that?

Henke
  • 4,445
  • 3
  • 31
  • 44

2 Answers2

1

C++ is picky when it comes to casting.

Replace void *InThread_func(struct arg_struct *); by void *InThread_func(void *my_data); and it should solve the problem.

Since this is C++ I'd recommend using std::thread is those are available to you.

Xaqq
  • 4,308
  • 2
  • 25
  • 38
  • Now I used std::thread and the compiler option -pthread and it works. Thanks. =) Could you tell me in a few words the main differences between those to ways to implement it? Do you have more freedom to optimize the code with pthread_t? – NewBieGermany Feb 24 '15 at 16:27
  • `pthread` stands for for Posix Thread. It's a *NIX thing. It's not portable (even though there seems to be a pthread port for Windows). `std::thread` is standard. It will work on all platform your code compile on. The main difference is portability (and ease of use, but that's my opinion). About freedom to optimize: you can retrieve the native handler from a `std::thread`, so you can do whatever you would have done with a `pthread_t.` – Xaqq Feb 24 '15 at 17:22
  • @Xaqq Re `std::thread`, the "ease of use" depends partially on what you are doing in the thread, and comes at some cost. Most of the time, I'd recommend them as well, if only for portability, but there are cases where they may not be appropriate. (For large scale servers, for example, Unix is pretty much the only game in town, and the performance issues may be significant.) – James Kanze Feb 25 '15 at 11:00
  • @JamesKanze But aren't `std::thread` implemented with `pthread` on Unix? If so, how can the performance difference be large enough to be noticed? Would have a link to some article talking about this, it seems rather interesting :) – Xaqq Feb 25 '15 at 11:10
  • @Xaqq `std::thread` will, obviously, use `pthread_create` at some point. `std::thread` does more, however; it guarantees a value copy of arbitrary arguments. This can only be done once the new thread has actually started execution. Which means some additional synchronization steps after `pthread_create`: a conditional, perhaps, or at least a mutex. (IIRC, `boost::thread` used the condition. And when I needed to do something similar in a project without boost, that's the solution I came up with as well.) – James Kanze Feb 25 '15 at 11:26
1

"Why is that?" Because you have an invalid conversion from void* (*)( arg_struct* ) to void* (*)( void* ), perhaps. The third argument to pthread_create (not the last) must be an extern "C" void* (*)( void* ). (Some compilers will ignore the necessity of the extern "C". They are broken in this regard.) So your InThread_fnc (which I can't find in your code) must be something like:

extern "C" void*
InThread_fnc( void* from_pthread_create )
{
    arg_struct const* p = static_cast< arg_struct const* >( from_pthread_create );
    (*p->func)( p->IntNumber );
    return nullptr;
}

Of course, this only works if the last argument of pthread_create was a arg_struct*. Which corresponds to your case, but beware if you start deriving: passing a new Derived or a &someDerived when the function you start casts to Base* results in undefined behavior.

James Kanze
  • 150,581
  • 18
  • 184
  • 329