Reputation: 753
It is possible to pass an argument to a function running in another thread, by reference.
Is it possible to return a result from a function running in another thread, by reference. If so, how?
Upvotes: 0
Views: 1056
Reputation: 309
Yes, but be very be careful cause each thread may using the same resource and leading to "data racing". You should use "mutex" or another mechanism to synchronize Ex: Without mutex
#include<iostream>
#include<string>
#include<vector>
#include<thread>
static std::vector<std::string> glm;
void addMap(std::vector<std::string> &glm, std::string name)
{
glm.push_back(name);
std::cout << "Add: " << name << "\n";
}
int main()
{
std::thread t[4];
std::vector < std::string> names = { "Hellen", "Peter", "Bob", "Zoe" };
for(int i = 0; i < names.size(); i++)
{
t[i] = std::thread(addMap, std::ref(glm), std::ref(names[i]));
}
for(int i = 0; i < names.size(); i++)
{
t[i].join();
}
}
As the example above, we expect it will print: Add: Hellen Add: Peter Add: Bob Add: Zoe
But it's NOT. Sometimes, it will print not enough names, sometimes the order is different. Example with mutex:
#include<iostream>
#include<string>
#include<vector>
#include<thread>
#include<mutex>
static std::vector<std::string> glm;
std::mutex mut;
void addMap(std::vector<std::string> &glm, std::string name)
{
mut.lock();
glm.push_back(name);
std::cout << "Add: " << name << "\n";
mut.unlock();
}
int main()
{
std::thread t[4];
std::vector < std::string> names = { "Hellen", "Peter", "Bob", "Zoe" };
for(int i = 0; i < names.size(); i++)
{
t[i] = std::thread(addMap, std::ref(glm), std::ref(names[i]));
}
for(int i = 0; i < names.size(); i++)
{
t[i].join();
}
}
Be very careful when coding with multithread
Upvotes: -1
Reputation: 27528
It is possible to pass an argument to a function running in another thread, by reference.
Not directly, because all arguments are copied or moved into the other thread, but you can simulate reference passing with std::ref
or std::cref
. See std::thread
constructor documentation:
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
orstd::cref
).
And of course, you have to make sure that the referenced object isn't destructed before the other thread is done using it.
Here's a small example:
#include <iostream>
#include <thread>
void f(int& x)
{
std::cout << x << '\n';
}
int main()
{
int a = 1;
std::thread t(f, std::ref(a));
t.join();
// safe, because `a` still exists at this point,
// but the thread is already finished
}
Is it possible to return a result from a function running in another thread, by reference.
No.
First of all, that wouldn't make sense, because it would defeat the purpose of threads if the caller was blocked waiting for the called function to return (however, see below).
Second, that's just not how threads work. As the C++ standard says at §4.7/1 [intro.multithread]
:
When one thread creates another, the initial call to the top-level function of the new thread is executed by the new thread, not by the creating thread.
In other words, every thread has "its own stack". This is completely different from using functions in the same thread. You cannot use return
to return anything from a new thread to the original thread.
You indirectly "return" something by the other thread setting data accessible to the original thread. You can do that via a simulated reference if you want to:
#include <iostream>
#include <thread>
void f(int& x, int& result)
{
result = x * x;
}
int main()
{
int a = 2;
int result;
std::thread t(f, std::ref(a), std::ref(result));
t.join();
std::cout << result << '\n';
}
Outside of such toy examples, the shared data will more realistically be a std::atomic
or be guarded by std::mutex
/ std::scoped_lock
et al.
That being said, you should definitely have a look at std::future
. Futures don't change the way threads work internally, but they provide an abstraction layer which resembles a normal function-call stack.
Upvotes: 4