I am new working with threads.. but I got the concept and have been playing with it in the last days.
But now I am trying to create a thread calling a bool function and passing a string as argument. The code is basically:
bool className::analyseData(const std::string& filename) {
...
return true;
}
bool className::equalise(...) {
...
const std::string filename0 = filenameBase + "_chip" + ss.str() + "_0";
std::thread analyse_dat0(analyseData, &filename0);
...
return true;
}
and then I call equalise from other place.
But when I try to compile it I get the following error:
SpidrEqualisation_multi_threading.cpp:140:50: error:
no matching function for call to ‘std::thread::thread(<unresolved overloaded function type>, const string&)
std::thread analyse_dat0(analyseData, filename0);`
Any idea about how I can fix that?
Many thanks for the help.
You don't want to pass a pointer to that thread function:
std::thread analyse_dat0(analyseData, filename0); // omit the &
// address of operator
Instead of using std::thread for this purpose why not use std::async and get the result as std::future ? That's much simpler, IMO.
Class c;
auto ft = std::async([&] { return c.analyseData("file.txt"); });
bool result = ft.get();
Remove the & from td::thread analyse_dat0(analyseData, &filename0); as you want a reference not a pointer in analyseData.
Also you need to provide an object as analyseData isn't static.
Related
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;
}
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.
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.
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
I ran into a compiler error when I tried to execute a function using std::thread. The error says : "error C2672: 'std::invoke': no matching overloaded function found".
Here is a code snippet:
void GetMinMax_X(const std::vector<Vertex>& iAllVertices, double & oMin_X,
double & oMax_X)
{
auto MinMax_X = std::minmax_element(iAllVertices.begin(),
iAllVertices.end(), [](const Vertex& i, const Vertex& j)
{
return i.GetX() < j.GetX();
});
oMin_X = MinMax_X.first->GetX();
oMax_X = MinMax_X.second->GetX();
}
int main()
{
std::vector<Vertex>;
// Some functions to fill the Vertex vector......
double Min_X = 0;
double Max_X = 0;
std::thread first (GetMinMax_X, AllVertices, Min_X, Max_X);
first.join();
return 0;
}
Thanks!
The error comes up because std::thread uses std::invoke behind the scenes to invoke GetMinMax_X, but with the arguments copied/moved. In particular, you cannot use
void GetMinMax_X(const std::vector<int>& iAllVertices, double & oMin_X, double & oMax_X)
because you would be forming references to the copies, which is not what you want.
You could still use
void GetMinMax_X(const std::vector<int>& iAllVertices, const double & oMin_X, const double & oMax_X)
but that would not help you get back the values into the main thread.
The solution is to use std::ref:
std::thread first(GetMinMax_X, AllVertices, std::ref(Min_X), std::ref(Max_X));
https://godbolt.org/z/ClK3Cb
See also what cppreference has to say about std::thread (where this "limitation" and the workaround are described):
https://en.cppreference.com/w/cpp/thread/thread/thread
The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g. with std::ref or std::cref).
Any return value from the function is ignored. If the function throws an exception, std::terminate is called. In order to pass return values or exceptions back to the calling thread, std::promise or std::async may be used.
First of all, I want to say that i already made researches on the subject, but nothing relevant...
(Error creating std::thread on Mac OS X with clang: "attempt to use a deleted function")
(Xcode 7: C++ threads ERROR: Attempting to use a deleted function)
(xcode - "attempt to use a deleted function" - what does that mean?)
And here's my issue...:
clang error:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:347:5: error: attempt to use a deleted function
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
And that's my code:
bool GenAI::loadAIs()
{
bool ret = true;
if (_nbThread > 1)
{
std::vector<std::thread> threads;
for (unsigned int i = 0; i < _nbThread; ++i)
threads.push_back(std::thread(static_cast<void (GenAI::*)(bool &, unsigned int)>(&GenAI::loadAIs), this, ret, i));
for (unsigned int i = 0; i < _nbThread; ++i)
threads[i].join();
}
else
loadAIs(ret, 0);
return ret;
}
// And the prototype of the function that i try to call
void GenAI::loadAIs(bool & ret, unsigned int iThread);
If some one could help me that'd be really helpful ! :)
Regards ;)
To pass reference to thread, you have to use std::reference_wrapper, that you can obtain with std::ref. So your code becomes:
threads.emplace_back(static_cast<void (GenAI::*)(bool &, unsigned int)>(&GenAI::loadAIs),
this,
std::ref(ret),
i));
Note:
bool ret should probably be std::atomic<bool> ret, or should should have one bool by thread. Else you may have concurrent access on ret.
The deleted function that it is complaining about is a deleted copy constructor for const thread.
For the deleted function problem, you can use:
threads.emplace_back(
Instead of:
threads.push_back(
What the commenter also referred to is that the function is creating more than one thread and passing to them a reference to the same boolean return variable.
It will crash if you don't use atomic_bool and even if you do, they will all report back to the same memory location, making the function miss the notification if one of them returns false.
In my project there is a vector
std::vector<std::shared_ptr<MovingEntity>>gameObjects;
Which I want to delete elements from if they meet the criteria.
Method to delete elements:
void GameWorld::catchBees()
{
auto q = std::remove_if(bees.begin(), bees.end(), beeToClose);
bees.erase(q);
}
Method beeToClose:
bool GameWorld::beeToClose( const MovingEntity & bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
if (bee.getConstPosition().distanceTo(m_beekeeper->getPosition()) > keeper->getCatchDistance())
{
return true;
}
return false;
}
When I try to compile the code I get some errors which I tried to understand:
'GameWorld::beeToClose': non-standard syntax; use '&' to create a
pointer
Not sure why this message is given
'std::remove_if': no matching overloaded function found
I did not declare beeToClose right?
'q': cannot be used before it is initialized SDLFramework
q is not initialized because:
std::remove_if(bees.begin(), bees.end(), beeToClose);
does not run correct?
How can I remove a std::shared_ptr correctly from a vector correctly when meeting some criteria?
The syntax for forming a pointer to member function is &ClassName::FunctionName. So you need &GameWorld::beeToClose for a pointer to the beeToClose member function. In your case, you should use a lambda from which you call that function
auto q = std::remove_if(bees.begin(), bees.end(),
[&](shared_ptr<MovingEntity> const& bee){ return beeToClose(bee); });
Also, you're using the wrong vector::erase overload, you want the one that erases a range of elements, not the one that erases a single element.
bees.erase(q, bees.end());
The vector contains std::shared_ptr<MovingEntity> elements, so beeToClose() needs to accept a const std::shared_ptr<MovingEntity> & parameter as input, not a const MovingEntity & parameter. Also, beeToClose() appears to be a non-static class method that accesses a non-static class member (m_beekeeper), so you can't just pass beeToClose() directly to std::remove_if() as it does not have access to the calling object's this pointer, but you can wrap it in a lambda to capture the this pointer.
Try this:
void GameWorld::catchBees()
{
auto q = std::remove_if(bees.begin(), bees.end(),
[this](const const std::shared_ptr<MovingEntity> &bee) {
return this->beeToClose(bee);
}
);
bees.erase(q, bees.end());
}
bool GameWorld::beeToClose(const std::shared_ptr<MovingEntity> &bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
return (bee->getConstPosition().distanceTo(m_beekeeper->getPosition()) > keeper->getCatchDistance());
}
You might also consider moving the distance calculation into Beekeeper instead:
bool GameWorld::beeToClose(const std::shared_ptr<MovingEntity> &bee)
{
std::shared_ptr<Beekeeper> keeper = std::static_pointer_cast<Beekeeper>(m_beekeeper);
return !keeper->isInCatchDistance(bee);
}
bool Beekeeper::isInCatchDistance(const std::shared_ptr<MovingEntity> &bee)
{
return (bee->getConstPosition().distanceTo(getPosition()) <= getCatchDistance());
}
what I am trying to do is an example below.
let's first define a bool.
bool cat = {false};
lets make a fake bool here.
bool setcat(bool booltoset)
{
booltoset = true;
return booltoset;
}
now lets call it with cat.
printf("cat is %s", cat?"true":"false"); //set cat as false.
my question is; is it possible to actually pass a bool through an argument than set that bool?
You need to pass by reference, i.e.:
void setcat(bool& booltoset)
{
booltoset = true;
}
Any function argument is just a variable with scope identical to the function body. If it's an ordinary automatic variable, then changing it has not effect on the caller. This is sometimes useful: you can actually use the arguments, for example:
template<typename F>
void for_each(noexcept_it i, const noexcept_it end, const F &f) noexcept(noexcept(f))
{
for(; i!=end; ++i) f(i); // use i as iteration variable.
}
though the compiler will optimise such things anyway in most cases.