何时使用c++类锁定互斥对象
When to lock mutex with c++ class
我目前正在处理一个接受多个客户端的服务器。
在服务器端,我有一个线程池(手工制作,运行良好),可以容纳多个线程:
ThreadPool::bind(new TCPReceiver());
ThreadPool::bind(new TCPSender());
一旦一个类绑定到ThreadPool
,就会调用它的start()
函数。
所以我的服务器基本上做的是:
- 绑定线程
- 接受一个或多个客户端
- 将客户端的指针添加到TCPReceiver客户端列表
- TCPReceiver执行
socket.receive()
,将接收到的数据推送给消息队列中的Clients
- TCPReceiver执行
- 将客户端的指针添加到TCPSender客户端列表
- TCPSender执行
socket.send()
并发送客户端的输出消息队列
- TCPSender执行
因此,一旦连接了客户端,其类的指针就会连接到两个线程,一个读取套接字,一个在套接字上发送。在所有这些过程中,主线程(服务器)弹出客户端的输入消息队列。
class Server {
std::list<Client*> clients;
TCPReceiver receive;
TCPSender send;
public:
void *start();
}
class Client {
std::list<NetworkMessage*> inQueue;
IMutex *inMutex;
std::list<NetworkMessage*> outQueue;
IMutex *outMutex;
Socket *socket;
}
class TCPReceiver {
std::list<Client*> clients;
public:
void *start();
}
class TCPSender {
std::list<Client*> clients;
public:
void *start();
}
我的问题是:
从Server/TCPReceiver/TCPSender类,我可以在不锁定Client类的情况下访问/使用Client指针,但只锁定Client的消息队列以弹出/推送它吗?
两个线程是否可以同时调用不同客户端的成员函数?
我可以在不锁定std::list的情况下调用std::list的成员函数吗(请参见(*it)->inQueue.empty()调用)?
void Server::start() {
for (std::list<Client*>::iterator it = this->clients.begin(); it != this->clients.end(); ++it) {
if (!(*it)->inQueue.empty()) {
(*it)->inMutex->lock();
(*it)->inQueue.front();
(*it)->inQueue.pop_front();
(*it)->inMutex->unlock();
}
}
}
同时在TCPReceiver上:
void TCPReceiver::start() {
for (std::list<Client*>::iterator it = this->clients.begin(); it != this->clients.end(); ++it) {
std::string msg = (*it)->socket->receive();
if (!msg.empty()){
(*it)->inMutex->lock();
(*it)->inQueue.push_back(msg);
(*it)->inMutex->unlock();
}
}
}
(我知道socket也应该有一个互斥,但这不是我现在想要理解的)
是的,两个线程确实可以同时执行同一实例的方法。您需要某种同步机制来防止由于同时修改相同的值而导致的竞争条件。在这方面,读取的危险性不亚于写入,因为在写入操作进行时进行读取可能会导致读取垃圾值。
基本上,这意味着在检查队列是否为空之前,您应该锁定(因为您的线程可能在该行和下一行之间挂起),但您不需要在迭代客户端的循环之外锁定,前提是确保客户端列表在迭代过程中不会更改。
您需要确保在对象处于无效状态时,没有线程访问任何对象。对于像您所描述的生产者-消费者类型的情况,您可能有兴趣了解条件变量,它提供了一种等待某种状态改变的方法。(例如,等待一个不再为空的空队列)。
请注意,在您提供的示例中,您只在clients
上循环一次,并在每个队列中最多添加/删除一条消息。
- 当只有一个线程主要使用该对象而其他线程很少使用它时,如何最小化该对象的互斥锁锁定?
- 在任何地方对C++中所有并行线程中的所有锁定和解锁实例使用相同的 std::mutex 和 lock 对象
- 在锁定下清除STD ::映射,而移动到临时对象
- C 删除对象,是否锁定
- 某人如何在一个线程中锁定多个对象
- 同时锁定两个互斥对象
- 如何在同一个线程上用同一个互斥对象锁定两次
- 如果其对象在多个线程中运行,我们是否需要锁定类成员功能
- C++11线程挂起锁定互斥对象
- 何时使用c++类锁定互斥对象
- C++,有没有办法锁定对象本身
- C++(可能还有 Java)如何锁定对象以进行同步
- 像 C# 一样在 Qt 中锁定对象
- 通过私有互斥锁锁定对象的最佳方法是什么
- 在linux上的C/C++中,我如何创建一个预锁定的互斥对象
- 如何为多线程访问实现类锁定对象
- 检查线程在锁定之前是否已经锁定了互斥对象
- 为什么condition_variable没有等待函数,它不重新锁定互斥对象
- 如果一个堆叠的协同程序锁定了一个互斥对象,然后就屈服了,该怎么办
- 锁定shared_ptr对象