简体   繁体   English

是否使用类包装器对符合C ++ 11的对象进行线程安全访问?

[英]Is using the class-wrapper for thread-safe access to the object conform to C++11?

Can I use this class-wrapper for thread-safe access to the object, and desired behavior conforms to C++11? 我可以使用此类包装器来对对象进行线程安全访问,并且所需的行为符合C ++ 11吗?

Main accent to the strings: 主要重点是字符串:

T* operator->() {

and

T& operator*() {

Note, I know that here optimal to use std::atomic<> for the integer(int), but in this code instead of int we can use any other object. 注意,我知道这里最好使用std :: atomic <>作为整数(int),但是在这个代码而不是int中我们可以使用任何其他对象。

Version 2.0 by using execute-around pointer idiom : 使用执行周期指针习惯用法 2.0版:

#include<thread>
#include<mutex>
#include<memory>
#include<iostream>
#include<vector>

template<typename T>
class safe_obj {
    T obj;
    mutable std::mutex mtx;
    safe_obj(safe_obj<T> &) {}
    safe_obj<T>& operator=(safe_obj<T> &) {}

    class T_exclusive_lock {
         std::unique_lock<std::mutex> xlock;
    public:
         T*const self;
         T_exclusive_lock(T * const s, std::mutex& _mtx)
             :self(s), xlock(_mtx) {}

        T* operator -> () const {return self;}
        operator T&()  {return *self;}

        friend std::ostream& operator << (std::ostream &stream, T_exclusive_lock &obj) {
            stream << obj;
            return stream;
        }
    };

public:
    template<typename  Types>
    safe_obj(Types  args) : obj(args ) 
    { }

    T_exclusive_lock operator->() {
        return T_exclusive_lock(&obj, mtx);
    }    

    T_exclusive_lock* operator*() {
        return &T_exclusive_lock(&obj, mtx);
    }       
};

int main() {
    safe_obj<std::shared_ptr<int> > safe_int( std::make_shared<int>(10) );   

    auto lambda = [&safe_int]() {
        std::cout << safe_int->use_count() << std::endl;    // is that thread-safe? 
        std::cout << *safe_int << std::endl;    // is that thread-safe? 
        std::cout << *safe_int->get() << std::endl;    // is that thread-safe? 
    };

    std::vector<std::thread> thr_grp;
    for(size_t i = 0; i < 10; ++i) thr_grp.emplace_back(std::thread(lambda));
    for(auto &i : thr_grp) i.join();

    int b; std::cin >> b;
    return 0;
}

The original code you provided didn't guarantee any thread-safety. 您提供的原始代码不保证任何线程安全。 Your std::unique_lock s unlock the mutex as soon as they get out of scope, which is prior to the use of the object you wanted to protect. 你的std::unique_lock一旦超出范围就会解锁互斥锁,这是在使用你想要保护的对象之前。

To achieve the desired result, you would need to declare another templated class (eg locked_obj<T> ) which would represent the object in a locked state (by having a unique_lock on the safe_obj 's mutex) and return such an object from the overloaded operators. 要实现所需的结果,您需要声明另一个模板化的类(例如locked_obj<T> ),它将表示处于锁定状态的对象(通过在safe_obj的互斥锁上具有unique_lock )并从重载中返回此类对象运营商。 Such an object would be a temporary one and allow you to manipulate the guarded object during the lifetime of locked_obj . 这样的对象是临时对象,允许您在locked_obj的生命周期内操纵受保护的对象。 As temporary objects live until the end of current statement, use of such safe_obj s would be mostly transparent. 由于临时对象一直存在直到当前语句结束,因此使用这样的safe_obj几乎是透明的。

This technique is an application of execute-around pointer idiom. 该技术是执行指针习惯用法的应用。

No, that's not thread-safe. 不,那不是线程安全的。 By the time the accessor functions return, the mutex has been unlocked, so access to the object is not synchronised. 当访问者函数返回时,互斥锁已被解锁,因此不同步对对象的访问。

One approach is to overload assignment and conversion operators: 一种方法是重载赋值和转换运算符:

safe_obj & operator=(T const &t) {
    std::unique_lock<std::mutex> lock(mtx);
    obj = t;
    return *this;
}

operator T() {
    std::unique_lock<std::mutex> lock(mtx);
    return obj;
}

but this might get tedious if you want to provide all the compound assignment operators, and the conversion operator won't work if the object is not copyable. 但是如果要提供所有复合赋值运算符,这可能会变得乏味,如果对象不可复制,则转换运算符将不起作用。

Another approach would be to return an accessor object containing a unique_lock , which keeps the mutex locked as long as you have access to the object. 另一种方法是返回包含unique_lock的访问器对象,只要您有权访问该对象,就会锁定互斥锁。

Locking individual functions or locking accesses to an individual object does not guarantee thread safety; 锁定单个功能或锁定对单个对象的访问并不能保证线程安全; depending on the program, many operations require multiple function calls on the same object without interruption or operations on multiple objects without interruption. 根据程序的不同,许多操作需要对同一对象进行多次函数调用,而不会中断或对多个对象进行操作而不会中断。 Thread safety has to be designed into an application; 线程安全必须设计到应用程序中; there are no library hacks that will make an application that isn't properly designed thread-safe. 没有库黑客可以使应用程序没有正确设计为线程安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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