0

Possible Duplicate:
pthread Function from a Class

I am getting an error ("Can not convert .....") and I think the third argument in the pthread_create call is wrong. I know the type of the third argument should be (void*)*(void *) but I am still getting an error.

void ServerManager::Init(){  
     pthread_t thread;
     pthread_create(&thread, NULL, AcceptLoop, (void *)this);
}

I have declared like this and I am trying to call the function below

void* ServerManager::AcceptLoop(void * delegate){

}

Please let me know how to fix this..

Thanks in advance.

Community
  • 1
  • 1
codereviewanskquestions
  • 13,460
  • 29
  • 98
  • 167
  • 1
    This has been asked many times before: http://stackoverflow.com/questions/1151582/pthread-function-from-a-class and others, I'm sure. – Adam Rosenfield Jun 15 '11 at 02:21
  • See also http://stackoverflow.com/questions/3835698/virtual-method-this-pointer and http://stackoverflow.com/questions/86046/best-way-to-start-a-thread-as-a-member-of-a-c-class and http://stackoverflow.com/questions/2460219/attaching-member-function-of-a-class-in-pthread – Adam Rosenfield Jun 15 '11 at 02:23
  • @Adam: I wanted to upvote your answer, but it uses C-style casts, which have got to die. Your answer is otherwise correct. – C. K. Young Jun 15 '11 at 02:23

2 Answers2

5

To be portable the callback function must use the C ABI;

extern "C" void* AcceptLoop(void*);

class ServerManager 
{
    public:
       void  Init();

    private:
       friend void* AcceptLoop(void*);

       void* AcceptLoop();   // Implement this yourself
       pthread_t thread;
};

void ServerManager::Init()
{  
     pthread_create(&thread, NULL, &AcceptLoop, reinterpret_cast<void*>(this));
}

void* AcceptLoop(void* delegate)
{
    return reinterpret_cast<ServerManager*>(delegate)->AcceptLoop();
}

void* ServerManager::AcceptLoop()
{
    // Do stuff
    // Be carefull this may (or may not) start before ServerManager::Init() returns.
    return NULL;
}

Edit: Based on comment

pthread_join()

This will wait for a particular thread to exit. The thread that called pthread_create() can call pthread_join() to wait for the child to finish. A good place for this would(might) be to put the join in the destructor of the ServerManager.

pthread_cancel()

pthread_cancel() is an asynchronous request for the thread to stop. The call will return immediately (thus does not mean the thread is dead yet). It is unspecified how quickily it will stop executing your code but it should execute some tidy handlers and then exit. It is a good idea to wait for a cancelled thread using pthread_jon().

class ServerManager 
{
    public:
       void  ~ServerManager()
       {
           join();
       }
       void* join()
       {
           void*   result;
           pthread_join(thread, &result);
           return result;
       }
       void cancel()
       {
           pthread_cancel(thread);
           join();
       }
       ... like before
};
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • Thanks for your answer. I have one more question. What is the best way to close this thread? I have read pthread_join or pthread_cancel but I am not sure which one is better. Thanks in advance. – codereviewanskquestions Jun 15 '11 at 03:27
  • @LCYSoft: Updated. PS. You may want to look at boost::thread. It is much more advanced and easy to use. The pthread interface is not really for the beginner. – Martin York Jun 15 '11 at 07:57
2

You need to make your AcceptLoop(void*) a static function.

Example:

class ServerManager {
    // ...
    static void* AcceptLoop(void*);
    void* AcceptLoop();   // Implement this yourself
};

void* ServerManager::AcceptLoop(void* delegate)
{
    return static_cast<ServerManager*>(delegate)->AcceptLoop();
}
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • Thanks for your answer. But is there any alternative way to do this such as using a function pointer? – codereviewanskquestions Jun 15 '11 at 02:20
  • @LCYSoft: You can get a function pointer for a static function. – C. K. Young Jun 15 '11 at 02:22
  • 1
    The static function specified in the `pthread_create()` call can do whatever it likes - if you give it a function pointer, either through the final `void*` parameter to `pthread_create()` which is passed as the only parameter to the static function, or beforehand however you like, then it can call it. Note: pointers to member function can't be called without knowing the object's address anyway. Unless you want to vary which member function's called at run-time, Chris's solution is simpler and better than stuffing around with function pointers - btw "delegate" = addr of ServerManager object. – Tony Delroy Jun 15 '11 at 02:29
  • 2
    Since pthreads is a C library the callback must use the C ABI. The **only** way to gurantee this is to make "AcceptLoop()" an extern "C" you are just lucky that your compiler uses the same ABI for static methods. – Martin York Jun 15 '11 at 02:35
  • @Martin: +1 That is true. I thought about fixing it, but then it seems your answer already took care of that. :-) – C. K. Young Jun 15 '11 at 02:55