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::showWidg开发者_开发问答et()
{
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.
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
.)
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
}
精彩评论