I have an issue with multithreading where I probably lack understanding. I want to assign a member variable of an object inside a thread and then print the variable from another thread (or main in this case). It seems like I am doing something wrong, like there are two objects.
Here is a quick example:
thread_test.hpp
#pragma once
#include <iostream>
#include <chrono>
#include <thread>
class thread_test
{
public:
thread_test ():
test_variable{}
{}
int get_test_variable() const;
void updater_method();
private:
/* private data */
int test_variable;
};
thread_test.cpp
#include "thread_test.hpp"
void thread_test::updater_method()
{
int i{};
while(true)
{
test_variable = ++i;
std::this_thread::sleep_for(std::chrono::microseconds{1800});
}
}
int thread_test::get_test_variable() const
{
return test_variable;
}
main.cpp
#include <iostream>
#include <thread>
#include <unistd.h>
#include "thread_test.hpp"
int main()
{
thread_test obj{};
std::thread updater_thread(&thread_test::updater_method, obj);
while(true)
{
std::cout << obj.get_test_variable() << std::endl;
sleep(1);
}
return 0;
}
Output:
❯ ./main
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
I don't understand why the variable stays at the initialized value, because I am assigning it in the thread for the test object. Is there a better way to start the thread or should I start the thread from the class itself? What is the right way to do this?
std::thread
stores the arguments to be passed to the thread execution function by value (actually the function as well, relevant, if it's actually a functor, which is supported as well) – ie it creates copies of, which applies, too, to your test object obj
. So the result is that the main thread and the worker thread operate each on their own, distinct instance of your thread_test
class and thus the main thread never receives updates.
To avoid, you can either use a std::reference_wrapper
or a pointer:
std::thread updater_thread(&thread_test::updater_method, std::ref(obj));
// or alternatively:
std::thread updater_thread(&thread_test::updater_method, &obj);
This way you only operate on one single instance. Yet another alternative (thanks, @ chi , for the hint) is using a lambda:
std::thread updater_thread([&obj]() { obj.updater_method() });
// ^^^ optional, alternatively just a default &
Note, too, that updating and reading variables in general is not atomic and you might get confronted with race conditions. You can solve the issue by either using std::atomic
, wrapping entire objects into or single members thereof, whichever suits better for you, or you protect access to the variables via a std::mutex
or possibly a std::shared_mutex
, if you want to allow simultaneous reads and only have the writes with exclusive access.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.