Reputation: 1
I wanted to perform hashing of a stream of input messages in multithreading, so was trying to implement
std::vector<std::future<HashData>> futures;
but the program aborts from abort.h when debugging in Visual Studio 2019.
Code Snippet:
std::vector<std::future<HashData>> futures;
std::vector<std::string> messages;
for (int i = 0; i < messages.size(); i++)
{
std::promise<HashData> promiseHashData;
std::future<HashData> futureHashData = promiseHashData.get_future();
futures.emplace_back(std::move(futureHashData));
std::async(std::launch::async, [&]() {PerformHash(std::move(promiseHashData), messages[i]);});
}
std::vector<HashData> vectorOfHashData;
// wait for all async tasks to complete
for (auto& futureObj : futures)
{
vectorOfHashData.push_back(futureObj.get());
}
void PerformHash(std::promise<HashData>&& promObject, std::string& message)
{
ComputeHashUsingSHA256(message);
HashData data;
// set data for HashData object
data.i = i;
data.blocks = blocks;
data.blocksize = blocksize;
data.blockbufs = blockbufs;
data.secs = secs;
memcpy(data.digest, digest, SHA256_DIGEST_SIZE);
data.has_hashdata = has_hashdata;
memcpy(data.hashdata_buf, hashdata_buf, c_hashsize);
promObject.set_value(data);
}
while debugging the code, observed as only few threads were created using async and post that, the program aborts from abort.h as shown in this image
Upvotes: 0
Views: 80
Reputation: 3973
To build on the good answer from @ALX23z and answer your comments there:
The reason you get that error is that PerformHash
(and your lambda) returns void
. The return value from std::async
is std::future<X>
, where X
is the return value of the function you give std::async
. Here is a small toy example:
struct HashData {std::size_t h;};
HashData performHash(const std::string &msg) // <- returns HashData
{
HashData hd = {msg.size()};
return hd;
}
int main()
{
std::vector<std::string> messages = {"Bla", "klaf", "this is a message"};
std::vector<std::future<HashData>> futures;
for (const auto &msg : messages)
{
auto fut = std::async(std::launch::async, [&]()
{ return performHash(msg); }); // <- also returns HashData
futures.emplace_back(std::move(fut));
}
std::vector<HashData> results;
for (auto &fut : futures)
results.push_back(fut.get());
for (const auto &hash : results)
std::cout << hash.h << '\n';
}
Also note that you can skip the lambda, and call std::async
like this:
auto fut = std::async(std::launch::async, performHash, msg); // performHash is a free function
// If performHash is a method of class HashCalculator - included for completeness sake
HashCalculator calc; // Need an instance somewhere
auto fut = std::async(std::launch::async, &HashCalculator::performHash, calc, msg);
Upvotes: 1
Reputation: 4703
The problem is that you capture promiseHashData
by reference. At each loop iteration it gets invalidated while the async thread performs computation on it.
You need to capture the instance of the promise by moving it into the lambda, like:
std::async(std::launch::async, [promiseHashData2=std::move(promiseHashData)] ()mutable{PerformHash(std::move(promiseHashData2), messages[i]);});
Or use std::async
's feature of returning std::future
while changing performHash
to return hashData
. Using both async
and promise
is redundant.
Upvotes: 1