4

I'm a beginning C++ programmer and I'm programming on a Linux machine.

I got this error:

cannot convert ‘void* (Network::*)(void*)’ to ‘void* (*)(void*)’ for argument ‘3’ to ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)

It is comming from this line:

pthread_create(&thread_id,0,&Network::SocketHandler, (void*)csock );

The function I'm trying to call is:

void* Network::SocketHandler(void* lp)

I declared both functions in the header file as private.

Do any of you see what I'm doing wrong?

Robᵩ
  • 163,533
  • 20
  • 239
  • 308
mschuurmans
  • 1,088
  • 1
  • 12
  • 24

2 Answers2

6

You are using a member function pointer where a regular function pointer is expected. A member function has an implicit extra parameter: this. pthread_create does not account for that.

You will have to make the function static to be able to use it with pthread_create. You can then use the void* parameter to pass along what would otherwise be the this pointer.

Personally, I would just ditch pthreads in favor of C++11 std::thread, or boost::thread if you don't have access to a C++11 implementation.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • Oh you're probably right, he's probably not trying to use it in conjunction with a `Network`. +1 – Seth Carnegie Jan 11 '13 at 22:56
  • And use the last parameter of `pthread_create()` to pass the `this` pointer to that `static` method. Either store the `csock` value as a member of the `Network` class and have the `static` method reach it via the `this` pointer, or else store both values in a dynamically allocated `struct` that the `static` method frees when it is done using it. – Remy Lebeau Jan 11 '13 at 22:58
  • c++11? is it easier/better then pthreads? where can i find some information about threads with c++11? thx – mschuurmans Jan 11 '13 at 23:01
  • 2
    @user1971401 yes it is much more better, just look up `std::thread` for C++11 on google. – Seth Carnegie Jan 11 '13 at 23:03
  • @SethCarnegie "more bettter" = awesome. (love that phrase). – WhozCraig Jan 11 '13 at 23:04
  • @SethCarnegie you almost *have to*. My contribution to this fiasco: find out more about [C++11 threads here](http://en.cppreference.com/w/cpp/thread). – WhozCraig Jan 11 '13 at 23:06
2

EDIT: If you're not trying to use an instance of Network with the function, then K-ballo's answer is what you need. If you are, then read on.

pthread_create expects a normal function to call, and you're trying to use a member function as a non-member function. A member function isn't a normal function because it must have an invoking object.

You can make a function that calls Network::SocketHandler on a Network and do it that way:

void* call_sockethandler(void* nw) {
    Network* network = static_cast<Network*>(nw);

    void* result = network->SocketHandler(somearg);

    // do something w/ result

    return nullptr;
}

Network nw; // this can't go out of scope though
pthread_create(&thread_id, 0, call_sockethandler, &nw); 
Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
  • Why `reinterpret_cast` and not `static_cast` there? – K-ballo Jan 11 '13 at 22:55
  • @K-ballo because I'm dumb. – Seth Carnegie Jan 11 '13 at 22:57
  • I ask because there are valid reasons to `reinterpret_cast` between pointers, but I can never seem to remember them – K-ballo Jan 11 '13 at 23:00
  • @K-ballo according to http://stackoverflow.com/q/310451/726361 `reinterpret_cast` is invalid for casting from `void*` because it's not an object type. I think `reinterpret_cast` is for everything but casting along an inheritance hierarchy, casting away constness, casting between convertible types, and casting from `void*`, but don't quote me on that – Seth Carnegie Jan 11 '13 at 23:02
  • That's odd, under some conditions a `reinterpret_cast` results in two `static_casts` to/from `void*`, I would expected a `reinterpret_cast` from `void*` to be valid... Luckily I never have to resolve to those low level tools! – K-ballo Jan 11 '13 at 23:05
  • 2
    +1, nice answer. If the OP is curious about tucking away the actual thread create in your class, a *basic* sample of how to do it is something [like this](http://ideone.com/pdqLAG). Note, the linked sample only deals with getting the wrapper setup; syncing, joining, etc, are all left to be done, but the proc-routine setup should be evident, which was the goal of the question. – WhozCraig Jan 11 '13 at 23:13