Creating threads in C vs C++

Discussion in 'C++' started by john, Jan 8, 2010.

  1. john

    john Guest

    Hi,

    I'm writing a multithreaded application in C++. I tried to do like C
    posix threads and pass an object method. But I got a compilation error:

    'argument of type 'void*(myclass::)(void *)' does not match 'void *
    (*)(void *)'

    I've done lots of multithreaded work in C. But this my first time doing
    it in C++. How do I create a thread in C++?

    Cheers

    John
     
    john, Jan 8, 2010
    #1
    1. Advertising

  2. john

    Guest

    On Jan 8, 5:36 pm, john <> wrote:
    > Hi,
    >
    > I'm writing a multithreaded application in C++. I tried to do like C
    > posix threads and pass an object method. But I got a compilation error:
    >
    >    'argument of type 'void*(myclass::)(void *)' does not match 'void *
    > (*)(void *)'
    >
    > I've done lots of multithreaded work in C. But this my first time doing
    > it in C++. How do I create a thread in C++?
    >
    > Cheers
    >
    > John


    It looks like your attempting to use a class member function pointer
    where a just a plain function pointer is expected. You will have to
    make the function either a class static function a free function
    (outside of any class).

    HTH
     
    , Jan 8, 2010
    #2
    1. Advertising

  3. john

    Ian Collins Guest

    wrote:
    > On Jan 8, 5:36 pm, john <> wrote:
    >> Hi,
    >>
    >> I'm writing a multithreaded application in C++. I tried to do like C
    >> posix threads and pass an object method. But I got a compilation error:
    >>
    >> 'argument of type 'void*(myclass::)(void *)' does not match 'void *
    >> (*)(void *)'
    >>
    >> I've done lots of multithreaded work in C. But this my first time doing
    >> it in C++. How do I create a thread in C++?
    >>
    >> Cheers
    >>
    >> John

    >
    > It looks like your attempting to use a class member function pointer
    > where a just a plain function pointer is expected. You will have to
    > make the function either a class static function a free function
    > (outside of any class).


    A static member function isn't strictly correct, the thread function
    should be a C linkage (extern "C") free function. This can still be a
    friend of the class.

    --
    Ian Collins
     
    Ian Collins, Jan 8, 2010
    #3
  4. john

    Ralph Malph Guest

    > A static member function isn't strictly correct, the thread function
    > should be a C linkage (extern "C") free function. This can still be a
    > friend of the class.

    That is correct.
    Here is a fuller example:
    extern "C" void* run_somefunction(void*);

    void* run_somefunction(void* _tgtObject) {
    my_data *my_args;
    my_args = (my_data*) _tgtObject;
    myclass* mc = my_args->b;
    void* threadResult = mc->somefunction((void*)
    my_args);
    return threadResult;
    }

    I have this code outside of any class but that was
    just the easiest way in my implementation.
    What I am doing may be a little convoluted but
    it ends up working really well.
    my_args is a struct and b is a pointer to the
    class that contains somefunction which is the thread
    function. Other stuff is in the struct too but
    that was just because I personally needed other args.
    Happy Days to you!
     
    Ralph Malph, Jan 9, 2010
    #4
  5. john

    Rui Maciel Guest

    john wrote:

    > Hi,
    >
    > I'm writing a multithreaded application in C++.

    <snip />

    I believe that, for that topic, you will get better answers in a newsgroup
    dedicated to parallel programming, such as comp.programming.threads.

    Other than that, in order to help others help you, it would be better if you
    provided an example of the offending code.


    Rui Maciel
     
    Rui Maciel, Jan 9, 2010
    #5
  6. john

    red floyd Guest

    On 1/8/2010 4:08 PM, Ralph Malph wrote:
    >> A static member function isn't strictly correct, the thread function
    >> should be a C linkage (extern "C") free function. This can still be a
    >> friend of the class.

    > That is correct.
    > Here is a fuller example:
    > extern "C" void* run_somefunction(void*);
    >
    > void* run_somefunction(void* _tgtObject) {
    > my_data *my_args;
    > my_args = (my_data*) _tgtObject;
    > myclass* mc = my_args->b;
    > void* threadResult = mc->somefunction((void*) my_args);
    > return threadResult;
    > }



    Don't use a C-style cast.

    Better would be:

    extern "C" void *threadfunc(void*);

    class my_thread_class
    {
    // redacted
    private:
    friend void *threadfunc(void*);
    void *my_threadfunc();
    };

    extern "C" void *threadfunc(void *param)
    {
    return static_cast<my_thread_class*>(param)->my_threadfunc;
    }
     
    red floyd, Jan 9, 2010
    #6
  7. john

    red floyd Guest

    On Jan 8, 4:08 pm, Ralph Malph <> wrote:
    [redacted]

    Oops, forgot to mention, you don't need to pass the my_args, because
    all the state
    you need should already be in the thread object ("mc").
     
    red floyd, Jan 9, 2010
    #7
  8. john

    Ralph Malph Guest

    red floyd wrote:
    > On Jan 8, 4:08 pm, Ralph Malph <> wrote:
    > [redacted]
    >
    > Oops, forgot to mention, you don't need to pass the my_args, because
    > all the state
    > you need should already be in the thread object ("mc").


    What state?
    my_args is a struct for args being passed from
    another object that is starting the thread.
    Something like this(from a similar but not identical
    project):

    typedef struct {
    cannister* b;
    int flavor;
    char* item;
    FILE* out_stream;
    } producer_data;

    Posing just snippets of the code and not whole
    files may not make much of this clear
    without my further explanation but the OP
    should get the gist if what is happening.
     
    Ralph Malph, Jan 9, 2010
    #8
  9. john

    red floyd Guest

    On 1/8/2010 7:14 PM, Ralph Malph wrote:
    > red floyd wrote:
    >> On Jan 8, 4:08 pm, Ralph Malph <> wrote:
    >> [redacted]
    >>
    >> Oops, forgot to mention, you don't need to pass the my_args, because
    >> all the state
    >> you need should already be in the thread object ("mc").

    >
    > What state?
    > my_args is a struct for args being passed from
    > another object that is starting the thread.
    > Something like this(from a similar but not identical
    > project):
    >
    > typedef struct {
    > cannister* b;
    > int flavor;
    > char* item;
    > FILE* out_stream;
    > } producer_data;
    >

    Again, the typedef is a C-ism. just use struct producer_data.

    > Posing just snippets of the code and not whole
    > files may not make much of this clear
    > without my further explanation but the OP
    > should get the gist if what is happening.


    struct producer_data {
    canister *b;
    int flavor;
    char* item;
    FILE* out_stream;
    void* my_func()
    {
    // do stuff
    }
    };

    void* thread_func(void *p)
    {
    return static_cast<producer_data*>(p)->my_func();
    }


    void f()
    {
    producer_data* data = new producer_data;
    begin_thread(&thread_func, data);
    }
     
    red floyd, Jan 9, 2010
    #9
  10. john

    James Kanze Guest

    On Jan 9, 2:56 am, red floyd <> wrote:
    > On 1/8/2010 4:08 PM, Ralph Malph wrote:


    > >> A static member function isn't strictly correct, the thread
    > >> function should be a C linkage (extern "C") free function.
    > >> This can still be a friend of the class.

    > > That is correct.
    > > Here is a fuller example:
    > > extern "C" void* run_somefunction(void*);


    > > void* run_somefunction(void* _tgtObject) {
    > > my_data *my_args;
    > > my_args = (my_data*) _tgtObject;
    > > myclass* mc = my_args->b;
    > > void* threadResult = mc->somefunction((void*) my_args);
    > > return threadResult;
    > > }


    > Don't use a C-style cast.


    > Better would be:


    > extern "C" void *threadfunc(void*);


    > class my_thread_class
    > {
    > // redacted
    > private:
    > friend void *threadfunc(void*);
    > void *my_threadfunc();
    > };


    > extern "C" void *threadfunc(void *param)
    > {
    > return static_cast<my_thread_class*>(param)->my_threadfunc;
    > }


    You actually often need a double conversion when calling
    pthread_create (and other, similar functions). Basically, if
    you convert to void*, the only legal conversion is back to the
    type you converted. And in the simplest case, you will have
    just constructed a derived class (and have a pointer to it), but
    will cast back to the base class, in order to call a virtual
    function. So you need to ensure that the pointer you convert to
    void* is a pointer to the base class, not to the derived class.

    --
    James Kanze
     
    James Kanze, Jan 9, 2010
    #10
  11. john

    Rolf Magnus Guest

    James Kanze wrote:

    > You actually often need a double conversion when calling
    > pthread_create (and other, similar functions). Basically, if
    > you convert to void*, the only legal conversion is back to the
    > type you converted. And in the simplest case, you will have
    > just constructed a derived class (and have a pointer to it),
    > but will cast back to the base class, in order to call a virtual
    > function. So you need to ensure that the pointer you convert to
    > void* is a pointer to the base class, not to the derived class.


    The typical implementation that I know is based roughly on something like
    that:

    class Thread
    {
    public:
    // ...
    void run()
    {
    // ...
    pthread_create(&tid, 0, thread_helper, this);
    }
    private:
    virtual void doit() = 0;

    pthread_t* tid;
    };

    extern "C"
    void* thread_helper(void* arg)
    {
    static_cast<Thread*>(arg)->doit();
    return arg;
    }

    Then you derive from Thread and implement the doit() function. Doesn't get
    much simpler than that, and you get a conversion from a Thread* to void* and
    back to Thread*.

    BTW: When implementing something like that, I noticed that C++ lacks a way
    of defining functions with internal C linkage. I'd usually make a function
    like thread_helper static (or, if it were a C++ function, put it in an
    unnamed namespace), but I have to make the linkage extern to make it a C
    function, and there is no such thing as static "C" or extern "C" static.
     
    Rolf Magnus, Jan 9, 2010
    #11
  12. john

    James Kanze Guest

    On Jan 9, 7:08 pm, Rolf Magnus <> wrote:
    > James Kanze wrote:
    > > You actually often need a double conversion when calling
    > > pthread_create (and other, similar functions). Basically,
    > > if you convert to void*, the only legal conversion is back
    > > to the type you converted. And in the simplest case, you
    > > will have just constructed a derived class (and have a
    > > pointer to it), but will cast back to the base class, in
    > > order to call a virtual function. So you need to ensure
    > > that the pointer you convert to void* is a pointer to the
    > > base class, not to the derived class.


    > The typical implementation that I know is based roughly on
    > something like that:


    > class Thread
    > {
    > public:
    > // ...
    > void run()
    > {
    > // ...
    > pthread_create(&tid, 0, thread_helper, this);
    > }
    > private:
    > virtual void doit() = 0;


    > pthread_t* tid;
    > };


    > extern "C"
    > void* thread_helper(void* arg)
    > {
    > static_cast<Thread*>(arg)->doit();
    > return arg;
    > }


    > Then you derive from Thread and implement the doit() function.
    > Doesn't get much simpler than that, and you get a conversion
    > from a Thread* to void* and back to Thread*.


    That works. I'm not sure if it's really what I would consider
    good design (although to be frank, I'm not sure what is good
    design where threads are concerned); some would say that the
    thread and the code it executes are logically two different
    things. But just about anything which wraps the thread in a
    class, and doesn't use templates, will do the trick. The
    problem occurs either when calling pthread_create directly, or
    when the thread class is a template (since the thread_helper
    above can't be a template, so the template has to wrap in a
    class using virtual functions)

    > BTW: When implementing something like that, I noticed that C++
    > lacks a way of defining functions with internal C linkage. I'd
    > usually make a function like thread_helper static (or, if it
    > were a C++ function, put it in an unnamed namespace), but I
    > have to make the linkage extern to make it a C function, and
    > there is no such thing as static "C" or extern "C" static.


    I wouldn't swear to it, but I think:

    extern "C" {
    static void*
    thread_helper(void* user_pointer)
    {
    static_cast< thread* >( user_pointer )->run();
    return user_pointer;
    }
    }

    would do the trick.

    --
    James Kanze
     
    James Kanze, Jan 9, 2010
    #12
  13. On 2010-01-09, James Kanze <> wrote:
    > I wouldn't swear to it, but I think:
    >
    > extern "C" {
    > static void*
    > thread_helper(void* user_pointer)
    > {
    > static_cast< thread* >( user_pointer )->run();
    > return user_pointer;
    > }
    > }
    >
    > would do the trick.


    Yes, that works:

    % objdump -t test.o | grep thread_helper
    00000000 l F .text 00000008 thread_helper

    Symbol 'thread_helper' is local.

    --
    T.
     
    Tomislav Novak, Jan 10, 2010
    #13
  14. john

    Rolf Magnus Guest

    James Kanze wrote:

    >> BTW: When implementing something like that, I noticed that C++
    >> lacks a way of defining functions with internal C linkage. I'd
    >> usually make a function like thread_helper static (or, if it
    >> were a C++ function, put it in an unnamed namespace), but I
    >> have to make the linkage extern to make it a C function, and
    >> there is no such thing as static "C" or extern "C" static.

    >
    > I wouldn't swear to it, but I think:
    >
    > extern "C" {
    > static void*
    > thread_helper(void* user_pointer)
    > {
    > static_cast< thread* >( user_pointer )->run();
    > return user_pointer;
    > }
    > }
    >
    > would do the trick.


    Seems to work. I guess I only tried it without the curly braces, expecting
    it to be equivalent. Without them, however, I got an error message.
     
    Rolf Magnus, Jan 10, 2010
    #14
  15. john

    Helge Kruse Guest

    "Ian Collins" <> wrote in message
    news:...
    > wrote:
    >> It looks like your attempting to use a class member function pointer
    >> where a just a plain function pointer is expected. You will have to
    >> make the function either a class static function a free function
    >> (outside of any class).

    >
    > A static member function isn't strictly correct, the thread function
    > should be a C linkage (extern "C") free function. This can still be a
    > friend of the class.


    Is there a technical reason for the C linkage requirement? AFAIK the calling
    convention of the function must match what can be achieved by appropriate
    attributes of a static member function.

    Helge
     
    Helge Kruse, Jan 11, 2010
    #15
  16. john

    Rolf Magnus Guest

    Helge Kruse wrote:

    >
    > "Ian Collins" <> wrote in message
    > news:...
    >> wrote:
    >>> It looks like your attempting to use a class member function pointer
    >>> where a just a plain function pointer is expected. You will have to
    >>> make the function either a class static function a free function
    >>> (outside of any class).

    >>
    >> A static member function isn't strictly correct, the thread function
    >> should be a C linkage (extern "C") free function. This can still be a
    >> friend of the class.

    >
    > Is there a technical reason for the C linkage requirement? AFAIK the
    > calling convention of the function must match what can be achieved by
    > appropriate attributes of a static member function.


    The C++ standard explicitly mentions that calling conventions are part of
    the linkage, and they don't need to be the same for C and C++ linkage.
     
    Rolf Magnus, Jan 11, 2010
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mike King

    Creating Threads safe?

    Mike King, Mar 27, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    333
    Eliyahu Goldin
    Mar 27, 2006
  2. yoda
    Replies:
    2
    Views:
    480
    =?utf-8?Q?Bj=C3=B6rn_Lindstr=C3=B6m?=
    Aug 1, 2005
  3. threads without threads

    , Aug 27, 2004, in forum: C Programming
    Replies:
    4
    Views:
    448
    William Ahern
    Aug 27, 2004
  4. Pedro Pinto

    Java Threads - Get running threads

    Pedro Pinto, Apr 8, 2008, in forum: Java
    Replies:
    2
    Views:
    1,521
    Arne Vajhøj
    Apr 9, 2008
  5. Une bévue
    Replies:
    0
    Views:
    187
    Une bévue
    Jun 14, 2006
Loading...

Share This Page