【发布时间】:2017-09-24 14:05:53
【问题描述】:
假设我有一堂课:
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>> 并修改了初始化代码以创建指针对象而不是直接创建对象并解决了我的问题,但问题仍然存在,所以我决定在这里发布。
【问题讨论】:
-
您使用指针的方法也无法编译,还是您的评论是剩余的?
-
您可以为第一种情况创建一个 PImpl 样式的包装器。第二种方法也可以工作,但是您需要创建
_mutexShaderData。 -
线程是,互斥量没有。那是因为
std::thread是一个线程句柄,而不是实际的线程本身。通常,资源是不可移动的,而资源句柄是可移动的。 -
一旦您在
std::unique_ptr中拥有互斥锁并且您的所有数据成员都是std::vector<int>、std::unique_ptr<...>,您为什么还要定义移动构造函数?一旦你摆脱了不可移动的成员,编译器提供的移动构造函数应该可以正常工作。
标签: c++ multithreading c++11 pointers move