对于以std :: thread和std :: mutex为字段的类,move构造函数是否有意义?

科雷利亚啤酒

假设我有一堂课:

class WonnaBeMovedClass
{
public:

    WonnaBeMovedClass(WonnaBeMovedClass&& other);

    void start();

private:

    void updateSharedData();

    std::vector<int> _sharedData;
    std::thread _threadUpdate;
    std::mutex _mutexShaderData;

    //other stuff
};

WonnaBeMovedClass::WonnaBeMovedClass(WonnaBeMovedClass&& other)
{
    _sharedData = std::move(other._sharedData);
    _threadUpdate = std::move(other._threadUpdate);
    _mutexShaderData = std::move(other._mutexShaderData); //won't compile.
}

void WonnaBeMovedClass::start()
{
    _threadUpdate = std::thread(&updateSharedData, this);
}

void WonnaBeMovedClass::updateSharedData()
{
    std::lock_guard<std::mutex> lockSharedData(_mutexShaderData);

    for (auto& value : _sharedData)
    {
        ++value;
    }
}

由于互斥体无法移动,因此无法编译。这没有道理。然后,我认为可以通过使用指针而不是实际变量来解决此问题,并提出了以下建议:

class WonnaBeMovedClass
{
public:

    WonnaBeMovedClass(WonnaBeMovedClass&& other);

    void start();

private:

    void updateSharedData();

    std::vector<int> _sharedData;
    std::unique_ptr<std::thread> _threadUpdate //pointer;
    std::unique_ptr<std::mutex> _mutexShaderData //pointer;

    //other stuff
};

WonnaBeMovedClass::WonnaBeMovedClass(WonnaBeMovedClass&& other)
{
    _sharedData = std::move(other._sharedData);
    _threadUpdate = std::move(other._threadUpdate);
    _mutexShaderData = std::move(other._mutexShaderData); //won't compile.
}

void WonnaBeMovedClass::start()
{
    _threadUpdate = std::make_unique<std::thread>(&updateSharedData, this);
}

void WonnaBeMovedClass::updateSharedData()
{
    std::lock_guard<std::mutex> lockSharedData(*_mutexShaderData);

    for (auto& value : _sharedData)
    {
        ++value;
    }
}

所以现在当我:

WonnaBeMovedClass object1;
WonnaBeMovedClass object2;

//do stuff

object1 = std::move(object2);

我实际上同时移动了互斥锁和线程的地址。现在更有意义了……还是不?

该线程仍在处理object1而不是object2的数据,因此它仍然没有任何意义。我可能已经移动了互斥量,但是线程不知道object2。还是?我找不到答案,所以我想向您寻求帮助。

我是在做完全错误的事情,并且复制/移动线程和互斥体只是一个不好的设计,我应该重新考虑程序的体系结构?

编辑:

关于班级的实际目的存在疑问。它实际上是一个TCP / IP客户端(以类表示),它拥有:

  • 来自服务器的最新数据(几个数据表,类似于std :: vector)。
  • 包含管理线程的方法(更新状态,发送/接收消息)。

一次可以建立多个连接,因此在代码中某处有一个std::vector<Client>字段代表所有活动连接。连接由配置文件确定。

//read configurations

...

//init clients
for (auto& configuration : _configurations)
{
    Client client(configuration);
    _activeClients.push_back(client); // this is where compiler reminded me that I am unable to move my object (aka WonnaBeMovedClass object).
}}

_activeClients已从更改std::vector<Client>std::vector<std::unique_ptr<Client>>并修改了初始化代码,以直接创建指针对象而不是对象,并且可以解决我的问题,但是问题仍然存在,因此我决定将其发布在此处。

代词

让我们将问题分成两部分。

  1. 移动互斥锁。之所以不能这样做,是因为互斥锁通常是根据必须具有固定地址的OS对象来实现的。换句话说,操作系统(或运行时库,与我们所用的操作系统相同)保留了互斥对象的地址。可以通过在代码中存储(智能)互斥锁的指针,然后移动它们来解决此问题。互斥体本身不会移动。线程对象可以移动,因此没有问题。
  2. 移动自己的数据,而一些活动代码(线程或正在运行的函数或std::function存储在某处或任何地方)具有数据的地址并可以访问。实际上,这与前面的情况非常相似,只是代替了操作系统,它是保存数据的您自己的代码。和以前一样,解决方案是不移动数据。而是将(智能)指针存储并移动到数据。

总而言之,

class WonnaBeMovedClass
{
public:
    WonnaBeMovedClass
        (WonnaBeMovedClass&& other);
    void start();
private:
    struct tdata {
        std::vector<int> _sharedData;
        std::thread _threadUpdate;
        std::mutex _mutexShaderData;
     };
     std::shared_ptr<tdata> data;
     static void updateSharedData(std::shared_ptr<tdata>);
};

void WonnaBeMovedClass::start()
{
    _threadUpdate = std::thread(&updateSharedData, data);
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

std :: move是否对堆栈变量有意义

std :: vector.push_back(std :: move(foo))是否有意义?

std :: thread的构造和执行

在C ++中,使用带有std :: optional <T>参数的函数来表示可选参数是否有意义?

C ++ std :: thread和方法类

混合std :: move()和std :: thread无法编译

对于不同的编译版本和不同的机器,std :: hash对于相同的输入是否给出相同的结果?

在C ++ 17中使用const std :: string&参数是否有意义?

C ++ 11:具有std :: thread和lambda函数的Segfault

C ++ 11 std :: thread和虚函数绑定

对于std :: vector <>类的struct成员重载operator =

std :: thread构造函数传递指针和ref传递之间有区别吗?

在类内部使用std :: thread()和std :: ref()会导致生成错误

为什么对于简单函数和lambda,std :: is_function返回false?

没有参数的std :: thread构造函数

为什么C ++ allow type对于std :: map没有默认构造函数,而没有std :: pair?

对于 std::string 的 compare 和 == 之间的差异

std :: thread和rvalue参考

std :: thread和异常处理

使用删除的函数'std :: thread :: thread(const std :: thread&)'

为什么使用std :: thread :: hardware_concurrency()和boost :: thread :: hardware_concurrency()有区别?

对于从std :: tuple派生的类,直接初始化失败,而对std :: pair起作用

移动构造函数和std :: move混乱

这是通用参考吗?std :: forward在这里有意义吗?

通过(Args && ...)构造std :: thread

std :: thread调用类方法

关于std :: thread类的问题

std :: thread类与c ++中的std :: this_thread命名空间?

移动构造函数和移动赋值运算符在不将指针作为成员变量保存且不管理资源的类中有意义吗?