求解惑:关于多线程并发环境下构造函数的线程安全
Posted 看,未来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求解惑:关于多线程并发环境下构造函数的线程安全相关的知识,希望对你有一定的参考价值。
在构造期间不要泄露 this 指针
对象构造要做到线程安全,惟一的要求是在构造期间不要泄露 this 指针,即
1、不要在构造函数中注册任何回调
2、也不要在构造函数中把 this 传给跨线程的对象
3、即便在构造函数的最后一行也不行
之所以这样规定,是因为在构造函数执行期间对象还没有完成初始化,如果 this 被泄露 (escape) 给了其他对象(其自身创建的子对象除外),那么别的线程有可能访问这个半成品对象,这会造成难以预料的后果。
来自:https://www.cnblogs.com/Vancamel/p/11316410.html
这就完了吗?这个自然是好理解的,有什么好疑惑的。
我的“犯忌”代码以及诡辩
下面是我的,说实话,写这个的时候不知道这个构造函数的线程安全。
ChatServer::ChatServer(EventLoop *loop,
const InetAddress &listenAddr,
const string &nameArg) : _server(loop, listenAddr, nameArg),
_loop(loop)
{
//注册连接回调
_server.setConnectionCallback(std::bind(&ChatServer::onConnection, this, _1));
//注册消息回调
_server.setMessageCallback(std::bind(&ChatServer::onMessage, this, _1, _2, _3));
//设置线程数
_server.setThreadNum(5);
}
//注册消息以及对应的回调操作
ChatService::ChatService(){
_msgHanderMap.insert({LOGIN_TYPE,std::bind(&ChatService::login,this,_1,_2,_3)});
_msgHanderMap.insert({REG_TYPE,std::bind(&ChatService::reg,this,_1,_2,_3)});
_msgHanderMap.insert({ONE_CHAT_MSG,std::bind(&ChatService::onechat,this,_1,_2,_3)});
_msgHanderMap.insert({ADD_FRINEND_MSG,std::bind(&ChatService::addFriend,this,_1,_2,_3)});
// 群组业务管理相关事件处理回调注册
_msgHanderMap.insert({CREATE_GROUP_MSG, std::bind(&ChatService::createGroup, this, _1, _2, _3)});
_msgHanderMap.insert({ADD_GROUP_MSG, std::bind(&ChatService::addGroup, this, _1, _2, _3)});
_msgHanderMap.insert({GROUP_CHAT_MSG, std::bind(&ChatService::groupChat, this, _1, _2, _3)});
// 连接redis服务器
if (_redis.connect()){
// 设置上报消息的回调
_redis.init_notify_handler(std::bind(&ChatService::handleRedisSubscribeMessage, this, _1, _2));
}
}
且听我狡辩一下:
这俩类对象呐,在服务器开始运行的时候就被构造了对象,所以我可以确定它们在对象构造完成之前这个回调是不会被触发的。
甚至我还可以调控在这俩对象被构造之后好久都不会被触发。
(那是自然,只要我不连客户端,怎么触发?哈哈哈哈)
我解释不了的代码
那如果有的对象在服务器运行过程中要被频繁调用呢?那我真的不知道该怎么解释了,就有点疑惑。
能解释的我就不拿出来展示了,我展示一下我解释不了的,希望有大佬看到在评论区帮我解惑吧,谢谢
TcpConnection::TcpConnection(EventLoop* loop,
const string& nameArg,
int sockfd,
const InetAddress& localAddr,
const InetAddress& peerAddr)
: loop_(CHECK_NOTNULL(loop)),
name_(nameArg),
state_(kConnecting),
reading_(true),
socket_(new Socket(sockfd)),
channel_(new Channel(loop, sockfd)),
localAddr_(localAddr),
peerAddr_(peerAddr),
highWaterMark_(64*1024*1024)
{
channel_->setReadCallback(
std::bind(&TcpConnection::handleRead, this, _1));
channel_->setWriteCallback(
std::bind(&TcpConnection::handleWrite, this));
channel_->setCloseCallback(
std::bind(&TcpConnection::handleClose, this));
channel_->setErrorCallback(
std::bind(&TcpConnection::handleError, this));
LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this
<< " fd=" << sockfd;
socket_->setKeepAlive(true);
}
这个 TCPConnection 可是和新连接的 fd 一一对应啊,来一个新连接就new一个TCPConnection,然后立刻就绑定channel,扔EventLoop里面去了,用poller监控起来了。
这我就不知道该怎么解释了。。。
(下面这段代码出自muduo库 TCPConnection.cc)
以上是关于求解惑:关于多线程并发环境下构造函数的线程安全的主要内容,如果未能解决你的问题,请参考以下文章