0

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*)’
2
  • 1
    Indendation really does a lot to make your code readable. I highly recommend using it in the future. Even just a couple of spaces would be chill. Commented Jun 15, 2011 at 13:58
  • You should NOT use a member function Not even a static one. Read here for the correct solution. stackoverflow.com/questions/6352280/pthread-create-error-in-c/… Commented Jun 15, 2011 at 14:59

3 Answers 3

7

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.

Sign up to request clarification or add additional context in comments.

6 Comments

I tried using static , but this gives a error on variables used in that whole function
@user: Did you try the other idea? i.e. adding a static helper function which in turn calls the member-function?
@Oli: Nope, help me with it if u can.
A static member function is not sufficient. The function must be extern "C", and any language linkage on member functions is ignored.
@James: Perhaps you should raise that concern in the comments for the answer to that question?
|
0

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.)

2 Comments

Cant understand this procedure, can you explain it with reference to my program. I badly need it.
@user796094 The idea is that what you pass to pthread_create is a pointer to a function which casts its argument to a pointer to an interface, and calls a function in it. Then you derive from the interface to do whatever you want; in this case, to make things simpler, there is a template to create the derived class, so you don't have to write it each time. And the actual function passed to pthread_create will destruct the object you've created; since polymorphism is involved, and lifetime doesn't follow scope, you new it.
0

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
}

4 Comments

Sorry! There was a typo in start_routine it's fixed now.
widget.cpp: In member function ‘void Widget::showWidget()’: widget.cpp:34:33: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say ‘&Widget::start_routine’ widget.cpp:34:52: error: cannot convert ‘void* (Widget::*)(void*)’ to ‘void* ()(void)’ for argument ‘3’ to ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* ()(void), void*)’
Is start_routine a static method of the Widget class? If it is try making it a "flat" function (taking it out of the class Widget) which should make your code compile and run. I've ripped this example straight out of a working codebase so it should work.
The correct call is pthread_create(&thread, NULL, start_routine, this); (no ampersand to take a function pointer).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.