0

I'm currently developing a bloc on GNU Radio and I want to use a thread. This thread is there to acquired data from a UDP socket so I can use it in my GNU Radio bloc. The "general work" function is the one that does all the signal and data processing.

The master source file is organized like this :

namespace gr {
    namespace adsb {

    out::sptr
    out::make()
    {
        return gnuradio::get_initial_sptr
        (new out_impl());
    }

    /*
     * UDP thread
     */
    void *task_UdpRx (void *arg)
    {
        while(true)
        {
            printf("Task UdpRx\n\r");
            usleep(500*1000);
        }
       pthread_exit(NULL);
    }

    /*
    * The private constructor
    */
    out_impl::out_impl()
        : gr::block("out",
                gr::io_signature::make(1, 1, sizeof(int)),
                gr::io_signature::make(1, 1, sizeof(char)))
    {
        pthread_t Thread_UdpRx;

        //Thread init
        if(pthread_create(&Thread_UdpRx, NULL, task_UdpRx, NULL))
        {
            err("Pthread error");
        }
        else
        {
            printf("UDP thread initialization completed\n\r");
        }
    }

    /*
    * Our virtual destructor.
    */
    out_impl::~out_impl()
    {
    }

    void out_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
    {
        ninput_items_required[0] = noutput_items;
    }

    int out_impl::general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items)
    {
        const int *in = (const int *) input_items[0];
        char *out = (char *) output_items[0];

        // Do <+signal processing+>
        for(int i = 0; i < noutput_items; i++)
        {
            printf("General work\n\r");
        }/* for < noutput_items */

        // Tell runtime system how many input items we consumed on
        // each input stream.
        consume_each (noutput_items);

        // Tell runtime system how many output items we produced.
        return noutput_items;
    } /* general work */

    } /* namespace adsb */
} /* namespace gr */`

The problem I get is that when I try to compile, I get this error :

In constructor ‘gr::adsb::out_impl::out_impl()’:
error: argument of type ‘void* (gr::adsb::out_impl::)(void*)’ does not match ‘void* (*)(void*)’

This error refers to the line and it concerns task_UdpRx :

if(pthread_create(&Thread_UdpRx, NULL, task_UdpRx, NULL))

Does anybody have any idea ?

Don't hesitate to ask for more details if needed. The code I've displayed is the shortest I could do in order for you to get the best understanding possible.

Thank you !

  • 3
    It expects a free pointer and you're trying to pass it a member function, no surprises there – Voo Jun 19 '14 at 15:55
  • possible duplicate of [How do you pass a member function pointer?](http://stackoverflow.com/questions/130322/how-do-you-pass-a-member-function-pointer) – Rakib Jun 19 '14 at 16:05
  • I think the 'possible duplicate' is not a duplicate; it is asking how to pass a pointer to member function where that is expected, whereas this needs to devise a mechanism to pass a pointer to function (not member function) and still get to the class. – Jonathan Leffler Jun 19 '14 at 16:08

1 Answers1

2

You can't pass a pointer to member function to pthread_create().

You'll need a free function:

void *thread_start(void *object)
{
    gr::adsb::out_impl *object = reinterpret_cast<gr::adsb::out_impl *>(object);
    object.task_UpdRx(0);
    return 0;
}

or thereabouts, and you'll need to pass this function to pthread_create() and pass the this pointer as the data argument:

if (pthread_create(&Thread_UdpRx, NULL, thread_start, this))

I reserve the right to be misusing reinterpret_cast<>() — substitute the correct cast notation. I have reservations about starting the thread in the constructor, but this is the outline of a scheme that should work.


After the code update on 2014-06-25

The code is still not an MCVE. I can't copy it and compile it. There are many headers missing. The types out and out_impl are not defined/declared. Some of the GNU Radio inheritance stuff could probably be left out.

Here's my version of an MCVE. It isn't perfect because it doesn't reproduce your problem. It compiles cleanly on an Ubuntu 12.04 LTS derivative with GCC 4.9.0. It assumes you have a header <err.h> that defines a function err(). I'm not certain that the destructor is necessary for the MCVE (and removing it would eliminate another 5 lines or so).

Source

#include <cstdio>
#include <pthread.h>
#include <unistd.h>
#include <err.h>

namespace gr
{
    namespace adsb
    {
        class out_impl
        {
        public:
            out_impl();
            virtual ~out_impl();
        };

        void *task_UdpRx(void *arg)
        {
            while (true)
            {
                printf("Task UdpRx %p\n\r", arg);
                usleep(500*1000);
            }
            pthread_exit(NULL);
        }

        out_impl::out_impl()
        {
            pthread_t Thread_UdpRx;

            if (pthread_create(&Thread_UdpRx, NULL, task_UdpRx, NULL))
                err(1, "Pthread error");
            else
                printf("UDP thread initialization completed\n\r");
        }

        out_impl::~out_impl()
        {
        }

    }
}

Compilation

$ g++ --version
g++ (GCC) 4.9.0
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ make gr.o
g++ -g -O3 -std=c++11 -Wall -Wextra -Werror -c gr.cpp
$ nm -C -g gr.o
0000000000000010 T gr::adsb::task_UdpRx(void*)
0000000000000050 T gr::adsb::out_impl::out_impl()
0000000000000050 T gr::adsb::out_impl::out_impl()
0000000000000040 T gr::adsb::out_impl::~out_impl()
0000000000000000 T gr::adsb::out_impl::~out_impl()
0000000000000000 T gr::adsb::out_impl::~out_impl()
0000000000000000 V typeinfo for gr::adsb::out_impl
0000000000000000 V typeinfo name for gr::adsb::out_impl
                 U vtable for __cxxabiv1::__class_type_info
0000000000000000 V vtable for gr::adsb::out_impl
                 U operator delete(void*)
                 U err
                 U printf
                 U pthread_create
                 U usleep
$

Next steps

There are several ways that this Q&A can go from here:

  1. The question is abandoned or closed.
  2. You take the MCVE code and add stuff back until you get your original compilation error.
  3. You take your non-compiling code and remove stuff until you get to an MCVE from which you can remove nothing without removing the error. Preferably, the code should not refer to any headers that are not found on a regular Linux installation. If it must, you need to identify where they're obtainable from — yes, I can probably find GNU Radio if I have to, but I shouldn't need to do so.
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • But definition `void *task_UdpRx (void *arg)` looks like free function, Isn't it? – Gluttton Jun 19 '14 at 16:20
  • @Gluttton: judging from the error message, `task_UdpRx` is written as a member function, within the scope of the class. Of course, if I'm wrong, then we need an SSCCE ([Short, Self-Contained, Correct Example](http://sscce.org/)) or MCVE (http://stackoverflow.com/help/mcve) so we can tinker with the code. – Jonathan Leffler Jun 19 '14 at 16:34
  • I used the free function you suggested but I still have an compiling error : request for member ‘task_UpdRx’ in ‘object’, which is of non-class type ‘gr::adsb::out_impl*’ This error refers to the line object.taskUdpRx(0); of the free function. – Croustibat Jun 20 '14 at 17:27
  • OK; time for you to create an MCVE ([Minimal, Complete, Verifiable Example](http://stackoverflow.com/help/mcve)) or SSCCE ([Short, Self-Contained, Correct Example](http://sscce.org/)), two names for the same thing. (Write a comment here when you've modified the question so I know to come back and look; I may not remember otherwise.) – Jonathan Leffler Jun 20 '14 at 17:37
  • @JonathanLeffler I've modified the original question with the simplest code I could provide. Thank you for your future help ! – Croustibat Jun 25 '14 at 18:58
  • @JonathanLeffler Thank you for your help, it is not working properly yet but at least it compiles and I'm gonna work from there ! – Croustibat Jun 26 '14 at 15:11
  • Glad it is of some help. Be wary of starting threads in a constructor. All else apart, the object isn't in a completely initialized state until the constructor completes — in theory. In practice, you should be able to design things so that they work, but I think I'd probably want to organize it so there was a separate method to kick off the thread. And I'd want to look carefully at thread termination (destructors; thread terminates before the destructor; etc). – Jonathan Leffler Jun 26 '14 at 15:30