Search code examples
c++parameter-passingstd-function

Pass argument to std::bind at run time to a dispatch Queue


I have trouble to pass an argument to my dispatch queue that takes a function pointer as a parameter. I have implemented a Dispatch Queue like this tutorial

typedef std::function<std::string( const std::array<float, kMaxSamples> &)> fp_t;


class DispatchQueue {
public:
    DispatchQueue(std::string name, size_t thread_cnt = 1);
    ~DispatchQueue();
    //move
    void dispatch(fp_t && item); //Take the typedef defined above

private:

    std::string _name;
    std::queue<fp_t> _q;
    std::vector<std::thread> _threads;
    void dispatch_thread_handler(void);
    std::mutex _lock;
    std::condition_variable _cv;
    bool _quit;
};

My std::function takes an std::array as a parameter.

Then, later in my code I add in the queue this particular job to process this argument.

queue->dispatch(std::bind(&AudioRecordEngine::run, mRecordingCallbackImp.getAudioData()));

The dispatch function is defined as:

void DispatchQueue::dispatch(fp_t &&item)
{
   std::unique_lock<std::mutex> lock(_lock);

    _q.push(item);

    // Manual unlocking is done before notifying, to avoid waking up
    // the waiting thread only to block again (see notify_one for details)
    lock.unlock();
    _cv.notify_one();
}`

Maybe it is too complicated for this use case, I probably don't know how to do better.

I would greatly appreciate suggestion and help. I am stuck for quite a while.

Thanks a lot

EDIT: The problem I am facing is at compilation time:

no viable conversion from '__bind<std::__ndk1::__bind<std::__ndk1::basic_string<char, std::__ndk1::char_traits, std::__ndk1::allocator > (AudioRecordEngine::*)(const std::__ndk1::array<float, 44100> &), std::__ndk1::array<float, 44100> > >' to 'fp_t' (aka 'function<basic_string<char, char_traits, allocator > (const array<float, kMaxSamples> &)>')

It seems that my std::function do not support the argument I am passing. The problem look like I do not use the std::bind properly.

Basically I would like to pass to my dispatch function the function pointer with the given argument.

EDIT 2:

The AudioRecordEngine::run is defined as:

   std::string AudioRecordEngine::run(const std::array<float,    __NUM_SAMPLES__> & audioData) {
    std::thread::id this_id = std::this_thread::get_id();
    LOGD("In the thread ID %zu  \n", this_id);
    //double freq = FFTNativeWrapper::fftEntryPoint(audioData);
    //LOGD("In the Thread, FFT analysis == %zu  \n", freq);
    return "from thread";
}


std::array<float, kMaxSamples> RecordingCallbackImp::getAudioData() {
return mData;

}


Solution

    1. Inside the implementation of DispatchQueue, functional objects of type fp_t are invoked as fn(), so fp_t should be std::function<std::string()> or std::function<void()>. There should be no const std::array& parameter.

    2. std::bind should give you something that takes no parameters. Your std::bind is almost correct. When you want to invoke a non-static member function, you need an object. That object, in the form of a pointer or a reference, should be the second argument of std::bind:

      AudioRecordEngine engine;
      
      queue->dispatch(std::bind(
          &AudioRecordEngine::run,
          std::ref(engine),
          mRecordingCallbackImp.getAudioData()
      ));
      

      Be careful about engine life time.

    3. Alternatively, you can use a lambda function instead of std::bind:

      AudioRecordEngine engine;
      
      queue->dispatch([&] { 
          engine.run(mRecordingCallbackImp.getAudioData());
      });
      

      This and the previous approaches differ by the moment when getAudioData() is called: in 2, the result of getAudioData() execution is stored inside the functional object returned by std::bind, in 3, getAudioData() is invoked just before run is called.

    Minimal example