Pass multiple arguments to member function with pthread_create()

Hi everyone,

I am having problems with c++. I am trying to call a member function in a class from another member function in the same class with pthread_create. Disch gave a beautiful explanation and solution to this issue in http://www.cplusplus.com/forum/general/144717/#msg762712. It was a reply to “Confused with threading in classes”. Please, look a that link. The problem is that, in my case, task1() has several arguments as input. (for example it could be task1(int, int, double *, double *)) I have been trying a couple of strategies without success. At the end I could manage to compile and to link without errors, but the ./a.out running returns with a segmentation fault error. I have debugged the program with the generated core file. I could see that the problem is in the thread creation. I have not posted the code because the solution is given in “Confused with threading in classes”, and I only need the opportune variations to my case.
So, what are the variations needed in the strategy Disch gave in “Confused with threading in classes” topic to solve my case?

Thank you very much in advance.
Your explanation is setting off alarm bells. Running another member function in a separate thread? That's asking for data races. You should try a different approach instead, as there is no easy way to go forward with your current setup - you have backed yourself into a corner.

Also, as mentioned in that thread, you should switch to using std::thread
http://www.cplusplus.com/reference/thread/thread/
http://en.cppreference.com/w/cpp/thread/thread
Last edited on
LB is correct -- multiple threads touching the same object is dangerous. Be sure that this is really the best way to approach this problem. Thread synchronization is something that has to be considered and planned out before you write a single line of code -- it is extremely difficult to squeeze it in as an afterthought. Trying to do so will undoubtedly result in numerous hard to find bugs (and maybe even extremely poor performance)


That said there are some legitimate use cases where you'd want to do this. Assuming this is such a case:


As mentioned, C++11 threads make this trivial. Considering the standard is 4 years old now and all major compilers have supported it for quite some time, there's isn't much reason why you shouldn't be using it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Foo
{
    typedef std::unique_ptr<std::thread>    ThreadPtr;
    
    ThreadPtr launcher()
    {
        return ThreadPtr( new std::thread( 
            std::bind( &Foo::task, this, param1, param2, param3 )
            ) );
    }
    
    int task(int param1, int param2, int param3)
    {
        //...
    }
};



With pthreads, since you can't use a functor object (it only gives you a void pointer to pass as user data), you'll have to have some other object (like a struct) which houses all the data you want to pass in. Then you can pass a pointer to that house as the void* user data.

The bigger problem is ownership of the house. The launcher has to create it, but it can't release it until the task has used it. So the launcher effectively has to pass ownership to the task. This is trickier than it sounds.

You could synchronize with a mutex and have the launcher wait until the task notifies that it has taken ownership, but that is complicated and slow.

What you can't do, is have a simple stack-allocated object in the launcher and just pass it to the task normally... as there is no guarantee that the task will use that object before the launcher's stack unwinds and destroys it.

What I would do is... (well actually I would use C++11 threads ... but if you were to tie my hands and say I couldn't for some reason...) I would dynamically allocate the house in the launcher, and maintain ownership until pthreads verifies the thread has started, then release ownership and let the task be responsible for deleting it.

But again this is clumsy and extremely easy to get wrong. There's a lot of nuance to it and it's a maintenance nightmare. You really should just use C++11 threads.


Here's my first stab at it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// note:  I don't know pthread details.  I'm going to assume there's a pthread_create function
//   and that it returns a pointer to the generated 'pthread_t' object, or null if the thread
//   failed to create

class Foo
{
    struct House
    {
        Foo* obj;
        int param1;
        int param2;
        int param3;
    };
    typedef std::unique_ptr<House>  HousePtr;
    
    
    pthread_t* launcher()
    {
        HousePtr house(new House);
        house->obj = this;
        house->param1 = foo;
        house->param2 = bar;
        house->param3 = baz;
        
        pthread_t* thd = pthread_create( &Foo::callTask, house.get() );
        if(thd)  // if thread created successfully
        {
            house.release();    // <- release ownership (but don't delete!) the object
            //  The child thread now owns it
        }
        
        return thd;
    }
    
    static int callTask(void* voidHouse)
    {
        HousePtr house( reinterpret_cast<House*>(voidHouse) ); // <- take ownership of the object
        
        return house->obj->task( house->param1, house->param2, house->param3 );
    }
    
    int task( int param1, int param2, int param3 )
    {
        //...
    }
};



You could make the house a class member, which would greatly simplify this... but then your launcher would only be good for generating exactly 1 thread. You wouldn't be able to call it multiple times to generate multiple threads.



EDIT:

FWIW I made an [untested] thread pool class for another forum post that might be a helpful reference for C++11 threads:

http://www.cplusplus.com/forum/general/159379/#msg813869
Last edited on
1
2
3
4
5
6
7
8
    typedef std::unique_ptr<std::thread>    ThreadPtr;
    
    ThreadPtr launcher()
    {
        return ThreadPtr( new std::thread( 
            std::bind( &Foo::task, this, param1, param2, param3 )
            ) );
    }

what's all this new and bind business? It's just as-is:
1
2
3
4
    std::thread launcher()
    {
        return std::thread(&Foo::task, this, param1, param2, param3);
    }
Last edited on
That's right, I keep forgetting threads are movable.

Though I didn't realize you could just fill the param list like that -- I though you had to give a std::function. Whoops. ^^
Thank you very much for the help and the advices too. I finally used C++11 threads, I didn't know pthread implementation was so unnatural and difficult. I used the final code from Cubbi and it worked beautifully well. I could launch several concurrent threads working in the same object, and it seems to work fine.
Dear Disch, thank you very much for your time and your fast reply.
The performance is -of course- very low, as I have 27 threads over a dual-core Mp, so the computing is wasted in switching between threads instead of in the real computation. But the code has the expected behavior. This is all what I needed. Thank you!!!
Topic archived. No new replies allowed.