简体   繁体   中英

Calling pthread_create inside a member function?

I created a widget.h file containing the declartions of pthread_function and I wanted to call it in a member function destroyWidget of that class Widget in widget.cpp. but always shows an error. I'll show the .cpp and .h file.

widget.h file


class Widget
{
public:
Widget();
void createWidget(int x,int y,int w,int h);
void showWidget();
int wid;
pthread_t thread;
int *incomingval,id;
void join();
Window win;
XEvent evt;
private:
void* destroyWidget(void* ptr);
Display *disp;
int screenNumber;
unsigned long white;
unsigned long black;
long eventMask;
GC gc;
int tbit;
int *incoming,val;
};

now the widget.cpp


Widget::Widget()
{
disp=XOpenDisplay( NULL );
screenNumber=DefaultScreen(disp);
white=WhitePixel(disp,screenNumber);
black=BlackPixel(disp,screenNumber);
eventMask=StructureNotifyMask;
tbit=0;
}

void Widget::createWidget(int x,int y,int w,int h)
{
wid=w;
win= XCreateSimpleWindow(disp,DefaultRootWindow(disp),x,y,w,h,1,white,black);
}

void Widget::showWidget()
{
XMapWindow(disp,win);
XFlush(disp);
gc=XCreateGC(disp,win,0,NULL);
XSetForeground(disp,gc,white);
XDrawLine(disp,win,gc,wid-10,0,wid,10);
XDrawLine(disp,win,gc,wid-10,10,wid,0);
//calling the thread function
pthread_create( &thread, NULL, destroyWidget, this);
}

void Widget::join()
{
pthread_join( thread, NULL);
}
void* Widget::destroyWidget(void* ptr)
{
Widget* mw = static_cast(ptr);
eventMask=ButtonPressMask|ButtonReleaseMask;
XSelectInput(disp,win,eventMask);
do{
printf("id= %d",id);
XNextEvent(disp,&evt);
}while(evt.type!=ButtonRelease);
XDestroyWindow(disp,win);
XCloseDisplay(disp);
return NULL;
}

now the main.cpp file



#include "widget.h"
#include
int main()
{
Widget* w=new Widget();
Widget* n=new Widget();
n->createWidget(20,20,150,150);
w->createWidget(50,50,250,250);
n->showWidget();
w->showWidget();
n->join();
w->join();
return 0;
}

the error is

widget.cpp: In member function ‘void Widget::showWidget()’:
widget.cpp:44:51: error: argument of type ‘void* (Widget::)(void*)’ does not match ‘void* (*)(void*)’

The problem is that pthread_create is a C-style function; you need to give it a pointer-to-function. Widget::destroyWidget() is a pointer-to- member -function. (Remember that non-static member functions always have an implied this argument, which pthread_create doesn't know how to provide.)

See the answers to this question for some possible solutions: pthread function from a class .

Like Oli said you can't use a member function when a C-style function expects a "normal" function pointer. However, what you can do is make a separate function that calls back your destroyWidget() method.

Like so:

void* start_routine(void* arg)
{
    Widget* widget = static_cast<Widget* >(arg);

    widget->destroyWidget();

    return NULL;
}

void Widget::showWidget()
{
    pthread_create(&thread, NULL, &start_routine, this);
}

void Widget::destroyWidget()
{
    // your code
}

The third argument to pthread_create has the signature (in C++):

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

You're trying to pass it the address of a member function:

void* (Widget::*pointerToMemberFunction)( void* );

The signatures are incompatible: the second requires an object on which to call it, and is not extern "C" .

The simplest way of handling this is to use boost::thread , with all it's functional object support. Otherwise, you can define something like the following:

struct AbstractTask
{
    virtual ~AbstractTask() {}
    virtual void* run() = 0;
};

template<typename T, void* (T::*ptr)()>
class Task
{
    T* myObject;
public:
    Task( T* object ) : myObject( object ) {}
    virtual void* run()
    {
        return (myObject->*ptr)();
    }
};

extern "C" void* taskRunner( void* arg )
{
    std::auto_ptr<AbstractTask> p( static_cast<AbstractTask*>( arg ) );
    return p->run();
}

pthread_t taskStarter( AbstractTask* obj )
{
    pthread_t result;
    pthread_create( &result, NULL, &taskRunner, obj );
    return result;
}

To start a thread, you then call:

thread = taskStarter( new Task<Widget, &Widget::destroyWidget>( this ) );

(This is from memory, from an earlier project, so there might be some typos in it, but you get the idea. And you probably want to add some error handling in taskStarter .)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM