3

Considering the following class

class Foo
{
    public:
        void* func(void* arg)
        {
            // how to pass this function to pthread...?!
        }
}

Later I want to pass func() to pthread_create(), instead of a function:

int main()
{
    char * msg = "Hi dude";
    Foo * ins = new Foo();
    pthread_t pt;
    // how to pass ins->func instead of a function?
    pthread_create( &pt, NULL, ins->func, (void*)msg );
}

Thanks in advance.

Kninnug
  • 7,992
  • 1
  • 30
  • 42

3 Answers3

5

The 'usual' approach is, to pack the object and all function arguments into a struct, allocate this struct on the heap, pass an instance of this struct to a function with C binding and let that function call the objects member function:

struct wrap {
    char * msg;
    Foo ins; 

    wrap( char* m, const Foo& f ) : msg(m), ins(f) {}
};

extern "C" void* call_func( void *f )
{
    std::auto_ptr< wrap > w( static_cast< wrap* >( f ) );
    w->ins.func(w->msg);

    return 0;
}

int main() {
    wrap* w = new wrap( "Hi dude", Foo() );
    pthread_t pt;

    pthread_create( &pt, NULL, call_func, w );
}
Torsten Robitzki
  • 3,041
  • 1
  • 21
  • 35
4

It does not work the way you tried because C++ member functions get the this-pointer of the object passed as their first argument. This is implicitly done by the compiler if in C++ mode.

However, pthread_create() is a C function. Its third parameter is "pointer to a function that takes a void * as argument (and returns void *)". Once inside pthread_create(), there is no this, there is no information that this should implicitly be passed as first argument... and the member function gets called in a very different way than it is intended to be called -- you are in all kinds of trouble.

That is why pthread_create() only works on functions that use "C" linkage: Global functions and static member functions (neither of which use a this pointer).

Torsten has a nice method of working your way around this limitation. I just wanted to elaborate a bit on the technical background of the problem.

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • Thanks dear, many thanks.as you mentioned about the pthread is c style and I'm using it in cpp app, but I stiill prefer it over cpp11 threading mode. –  Feb 12 '14 at 12:37
  • @parsaporahmad: Neither C++11 nor Boost threading allows you to call the member function of a generic class as "starting point" of a thread; actually they require you to work with special "thread" classes. Effectively, they face the very same problem (C++ calling conventions) as `pthread_create()`. They just provide a more C++-ish wrapper around the multithreading capabilities of the host OS (which are most likely based in C linkage). – DevSolar Feb 12 '14 at 12:45
2

One way to do this is to declare the function as static

#include <iostream>
#include <pthread.h>
class Foo {
  public:
    static void* func(void* arg) {
      char *test = (char *) arg;
      std::cout << test << std::endl;
    }
};
int main() {
  char * msg = "Hi dude";
  Foo ins;
  pthread_t pt;
  pthread_create( &pt, NULL, ins.func, (void*)msg );
  pthread_join(pt, NULL);
  return 0;
}
Alex
  • 3,301
  • 4
  • 29
  • 43