简体   繁体   中英

How to properly assign a member value in a std::thread and read it from another?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM