mardi 17 avril 2018

c++11 Passing Lambda by ref into function then by ref into another lambda and the by ref into another function seems to get called twice

As you can probably tell by the title - I have a bit of a mess going on and I am struggling to debug it. It's not easy to make a small self contained example because it involves threads and callbacks associated with other 3rd party software, but I can provide the code snippets in question and hopefully someone can spot any possible issues:

top level/calling class

reader rd;
std::thread th;

// 1. Call reader::start_reader_thread and pass in the callback lambda and thread both by ref
rd.start_reader_thread( [](){callback();}, th);

// This gets called within the reader
callback()
{
    printf("Hello from call back\r\n");
}

reader class

class reader
{

    // 2. Create the thread with a thread function (another lambda) that runs start_reader and passes handler
    template <typename> Functor>
    start_reader_thread(Functor &handler, std::thread &reader_thread)
    {
        reader_thread = std::thread([&]()
        {
            start_reader(handler);
        }
    }

    // 3. start reader is a function that never returns that calls the callback "handler" function on certain events.
    template <typename> Functor>
    start_reader(Functor &handler)
    {
        do
        {
            // After some event occurs call the handler
            handler();
        } while (true)
    }
}

Note this code is a cut-down version of the real code and does compile/run.

This setup compiles, but when it runs I get an un-expected result and that is I would see "hello from callback" being printed twice "immediately" after each other. In the real code the second calling causes a crash for other reasons (probably to do with the function getting called by two threads when its not meant to and variables trampling over each other :o)

However, in my original setup that worked I called start_reader() directly in the following way:

th = std::thread([&]()
{
    rd.start_reader( [](){callback();}, th);
}

And this worked fine (I see "hello from callback" only once per event). My goal was to try to tidy away the generation of the thread by putting it into a function within reader class.

So I am not sure why I am getting two calls. My theories are:

  • The lambda function somehow gets copied and therefore there are two instances of it. But I have check that I am passing it by reference everywhere.
  • The thread got copied somewhere... but I can't see where - again I passed it by ref.

My questions are:

  • Is there anything wrong with the way I am passing around the thread object / lambda?
  • Why could the callback be getting called twice in the first scenario but not in the second - what is the difference?

Aucun commentaire:

Enregistrer un commentaire