C++ pthread member function [duplicate]
-
21-06-2021 - |
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*))>k_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?
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, >k_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.