Question

Possible Duplicate:
pthread Function from a Class

I have this code that I can't get to compile because of the pthread_create line:

void* gtk_functor::_threaded_run(void* win)
{
    Gtk::Window* w = static_cast<Gtk::Window*>(win);
    Gtk::Main::run(*w);
    delete w;
}

void gtk_functor::operator ()(Gtk::Window& win, bool threaded)
{
    if (threaded)
    {
        pthread_t t_num;
        pthread_create(&t_num, NULL, (void* (*)(void*))&gtk_functor::_threaded_run, static_cast<void*>(&win));
    }
    else
    {
        Gtk::Main::run(win);
    }
}

This gcc line:

g++ -o main 'pkg-config --cflags --libs sqlite3 gtkmm-3.0' -lpthread main.cpp

does in the end compile with this output:

code/ui.cpp: In member function 'void ui::gtk_functor::operator()(Gtk::Window&, bool)':
code/ui.cpp:45:65: warning: converting from 'void* (ui::gtk_functor::*)(void*)' to 'void* (*)(void*)' [-Wpmf-conversions]

and apparently the code doesn't work correctly, I get sementation fault when the if (threaded) is raised.

I know its with the cast, but I don't know the correct form of passing a member function into pthread_create. Any suggestions?

Was it helpful?

Solution

Try making _threaded_run static. In the header:

private:
  static void* _threaded_run(void*);

And in the implementation:

void* gtk_functor::_threaded_run(void* win) {
  Gtk::Window* w = static_cast<Gtk::Window*>(win);
  Gtk::Main::run(*w);
  delete w;
}

Then when creating the thread:

pthread_create(&t_num, NULL, &gtk_functor::_threaded_run, static_cast<void*>(&win));

OTHER TIPS

As @ildjarn suggests, just make a free function:

void * threaded_run(void * win)
{
    Gtk::Window * const w = static_cast<Gtk::Window*>(win);
    Gtk::Main::run(*w);
    delete w;
}

// ...

pthread_create(&t_num, NULL, threaded_run, &win);

Since the function does not depend on the state of any particular gtk_functor object, there is no point in making it a member function.


In a hypothetical different world where you really would want an object's member function to be called in a separate thread, you need to pass the object reference for the object around somehow, usually via the argument void pointer:

struct Foo
{
    void * run() { /* ... use state ... */ }

    /* ... state ... */
};

Foo x;
pthread_t pt;

// start a new execution context with x.run():
pthread_create(&pt, NULL, FooInvoker, &x);

extern "C" void * FooInvoker(void * p)
{
    return static_cast<Foo*>(p)->run();
}

In fact, you may even wish to package up more contextual information into some auxiliary structure and pass a void pointer to that to the thread invoker function.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top