CPP std::thread attempt to use a deleted function - c++

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.

Related

Compiler error when trying using std::thread

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.

Passing output stream object and other arguments to multiple threads

I'm trying to pass multiple arguments, one of which is an ofstream object, to multiple threads using the C++11 standard.
I want to pass an ofstream object because I want every thread to write in a different output file.
I'm initializing the threads and output streams in this way:
std::thread execution_threads[NUMBER_OF_THREADS]; // creating multiple empty threads
std::ofstream output_files[NUMBER_OF_THREADS]; // Empty output streams
// Opening and initializing the output files
Each thread executes a function that takes two arguments:
void execution(int thread_id, std::ofstream& output_file)
So I've looked around and I've read that in C++11 when a function func has multiple arguments a,b,c,d there's no need to use a struct and you can pass them just by writing std::thread t(func, a,b,c,d);. So I wrote this loop in order to launch the threads:
for (int i = 0; i < utils::NUMBER_OF_THREADS; i++) {
execution_threads[i] = std::thread(execution, i, output_files[i]);
}
The thing is that this code doesn't compile with this error:
Call to implicitly-deleted copy constructor of
'typename decay<basic_ofstream<char, char_traits<char> > &>::type'
(aka 'std::__1::basic_ofstream<char, std::__1::char_traits<char> >')
While if I use a struct as input in this way, everything works fine:
// Struct definition
struct thread_input {
int thread_id;
std::ofstream& output_file;
};
// This is the function that now has only one argument
void execution(struct thread_input input)
// And this is the loop that launches the threads
for (int i = 0; i < utils::NUMBER_OF_THREADS; i++) {
struct thread_input input = {i, output_files[i]};
execution_threads[i] = std::thread(execution, input);
}
// join() functions for each thread and end of the program
In this way everything works fine it compiles and it runs perfectly. But I really don't get why the compiler tells me that I'm trying to use the deleted copy-constructor if I use the other method.
Thank you for your help.
std::thread stores a copy of its arguments. When you pass it a non-copyable object like a std::ofstream it will complain.
You have two options:
1) Don't store an array of std::ofstream objects; just let your threads store their own streams. In this case, there's no need to copy the stream (just a move, which is fine):
for (int i = 0; i < utils::NUMBER_OF_THREADS; i++) {
execution_threads[i] = std::thread(execution, i, std::ofstream{});
//^^^^^^^^^^^^^^^ anonymous temporary
}
Of course, in this case you could just have the thread construct its own stream (maybe just pass in the filename).
2) Pass a std::reference_wrapper<std::ofstream> to your thread. std::reference_wrapper<T> is an object that holds a reference to T and has an implicit conversion to T&, so you'll just end up copying the reference instead of the stream itself. You can use the std::ref factory to deduce T and reduce typing:
for (int i = 0; i < utils::NUMBER_OF_THREADS; i++) {
execution_threads[i] = std::thread(execution, i, std::ref(output_files[i]));
//^^^^^^^^ std::ref added
}
This leaves you with all of the same ownership and lifetime issues that passing a struct containing a std::ofstream& would have (after all, that's all std::reference_wrapper is). It's up to you to make sure your output_files array survives until all of your threads have finished with it.

Creating an array of objects causes an issue

I create the two following objects:
bool Reception::createNProcess()
{
for (int y = 0; y < 3; ++y)
{
Process *pro = new Process; // forks() at construction
Thread *t = new Thread[5];
this->addProcess(pro); // Adds the new process to a vector
if (pro->getPid() == 0)
{
for (int i = 0; i < 5; ++i)
{
pro->addThread(&t[i]); // Adds the new thread to a vector
t[i].startThread();
}
}
}
Where I create 3 processes (that I have encapsulated in Process) and create 5 threads in each of these processes.
But I'm not sure the following line is correct:
Thread *t = new Thread[5];
Because my two functions addProcess and addThread both take a pointer to Process and Thread respectively and yet the compiler asks for a reference to t[i] for addThread and I don't understand why.
void Process::addThread(Thread *t)
{
this->threads_.push_back(t);
}
void Reception::addProcess(Process *p)
{
this->createdPro.push_back(p);
}
createdPro is defined in the Reception class as follows:
std::vector<Process *> createdPro;
and threads_ in the Process class like such:
std::vector<Thread *> threads_;
And the error message (as obvious as it is) is as follows:
error: no matching function for call to ‘Process::addThread(Thread&)’
pro->addThread(t[i]);
process.hpp:29:10: note: candidate: void Process::addThread(Thread*)
void addThread(Thread *);
process.hpp:29:10: note: no known conversion for argument 1 from ‘Thread’ to ‘Thread*’
Even though I defined my Thread as a pointer.
You have defined the member function to take a pointer:
void Process::addThread(Thread *t)
{
...
}
You then invoke this function for &t[i], which is a pointer and should work perfectly:
pro->addThread(&t[i]); // Adds the new thread to a vector
You could also invoke it with t+i and it would still be ok. However your error message tells us something different: the compiler doesn't find a match for pro->addThread(t[i]); (i.e. the & is missing).
Either you made a typo in your question, or you made a typo in your code. Or you have another invocation somewhere where you've forgotten the ampersand: t[i] would of course designate an object (it's equivalent to *(t+i) ) and not a pointer, and cause the error message you have (demo mcve)

Threading a bool function passing string argument

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.

Attempt to use a deleted function

From what I can gather online the cause of this is most likely related to trying to copy a thread (which you can't do). I'm not sure why this problem is arising though. I do suspect which lines it arises in though.
Worker thread definition:
void WorkerThread(SharedLList<uint32_t> *workQueue, std::mutex *dataLock, uint8_t *data, uint32_t *seenStates, int depth)
Code in calling function:
SharedLList<uint32_t> workQueue;
std::mutex lock;
uint8_t *stateDepths = new uint8_t[s.GetMaxRank()];
uint32_t seenStates = 1;
int currDepth = 0;
for (int i = 0; i < numThreads; i++)
{
threads[i] = new std::thread(WorkerThread, std::ref(workQueue), std::ref(lock), stateDepths, std::ref(seenStates), currDepth);
}
Thread
-> Semantic Issue
-> Attempt to use a deleted function
This is the line:
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
How can I fix this issue? What is wrong with my code?
Your thread function is declared as accepting pointers as parameters. Yet you pass references as arguments. This mismatch exists for all pointer parameters except uint8_t *data.