How to std::mutex::lock until function returns

前端 未结 2 2022
忘了有多久
忘了有多久 2021-02-20 08:42

I want to return a std::vector. This std::vector may be accessed from other threads (read and write). How can I unlock my std::mutex just

2条回答
  •  暖寄归人
    2021-02-20 09:15

    This is the sort of question that print statements can really help with. For example:

    #include 
    #include 
    
    std::mutex mut;
    
    template 
    class Lock
    {
        Mutex& mut_;
    public:
        ~Lock()
        {
            std::cout << "unlock\n";
            mut_.unlock();
        }
    
        Lock(const Lock&) = delete;
        Lock& operator=(const Lock&) = delete;
    
        Lock(Mutex& mut)
            : mut_(mut)
        {
            mut_.lock();
            std::cout << "lock\n";
        }
    };
    
    struct A
    {
        ~A()
        {
            std::cout << "~A() : " << this << "\n";
        }
    
        A()
        {
            std::cout << "A() : " << this << "\n";
        }
    
        A(const A& a)
        {
            std::cout << "A(const A&) : " << this << ", " << &a << "\n";
        }
    
        A& operator=(const A& a)
        {
            std::cout << "A& operator=(const A&) : " << this << ", " << &a << "\n";
            return *this;
        }
    };
    
    A a;
    
    A
    get()
    {
        Lock lk(mut);
        return a;
    }
    
    int
    main()
    {
        std::cout << "Start\n";
        auto vec = get();
        std::cout << "End\n";
    }
    

    By making my own version of std::lock_guard, I can insert print statements to find out when the mutex gets locked and unlocked.

    And by making a fake std::vector (called A above), I can insert print statements into the special members that I'm interested in. For me this outputs:

    A() : 0x10fcfb188
    Start
    lock
    A(const A&) : 0x7fff4ff06b28, 0x10fcfb188
    unlock
    End
    ~A() : 0x7fff4ff06b28
    ~A() : 0x10fcfb188
    

    which clearly shows that the mutex is locked while the A at 0x10fcfb188 is being copied from.

    The test can be altered for assignment with:

    int
    main()
    {
        A vec;
        std::cout << "Start\n";
        vec = get();
        std::cout << "End\n";
    }
    

    which now outputs:

    A() : 0x10d8a7190
    A() : 0x7fff5235ab28
    Start
    lock
    A(const A&) : 0x7fff5235ab18, 0x10d8a7190
    unlock
    A& operator=(const A&) : 0x7fff5235ab28, 0x7fff5235ab18
    ~A() : 0x7fff5235ab18
    End
    ~A() : 0x7fff5235ab28
    ~A() : 0x10d8a7190
    

    At first it looks like the assignment takes place outside the lock, and thus looks unsafe. However upon closer inspection one sees that the protected A at 0x10d8a7190 is copied to a temporary A inside the lock. The mutex is then unlocked and an assignment is made from the temporary to the local. No other thread could possibly reference the temporary. So as long as no other thread references vec, this is again safe.

提交回复
热议问题