[项目][WebServer][TcpServer]详细讲解

打印 上一主题 下一主题

主题 830|帖子 830|积分 2490


  • 单例模式的线程安全

    • 必要双重判空指针,降低锁冲突的概率,提高性能
    • 原因1:

      • 当第一次实例化单例时,大概有多个线程同时到来,而且svr指针为空
      • 这时他们就会去竞争锁,但只有一个线程会最快拿到锁,而且成功实例化出单例对象
      • 但此时如果不加双重判空指针,那些也进了第一层if判断的,仍然会去实例化出对象

    • 原因2:

      • 为了线程安全,必然要加锁,加锁之后再去判空
      • 但每次调用GetInstance()都必要去获得锁,释放锁,服从低下
      • 此时再加一层外层if判空,这样就会制止后续调用GetInstance()时没必要的锁竞争


  1. static const uint16_t PORT = 8090;
  2. static const int BACKLOG = 128;
  3. // 单例 -- 饿汉模式
  4. class TcpServer
  5. {
  6. public:
  7.     static TcpServer* GetInstance(uint16_t port = PORT)
  8.     {
  9.         static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  10.         if(svr == nullptr) // 双重判空指针,降低锁冲突的概率,提高性能
  11.         {
  12.             // 注意线程安全
  13.             pthread_mutex_lock(&lock);
  14.             if(svr == nullptr)
  15.             {
  16.                 svr = new TcpServer(port);
  17.                 svr->Init();
  18.             }
  19.             pthread_mutex_unlock(&lock);
  20.         }
  21.         return svr;
  22.     }
  23.     void Init()
  24.     {
  25.         Socket();
  26.         Bind();
  27.         Listen();
  28.         LOG(INFO, "TcpServer Init ... Success");
  29.     }
  30.     void Socket()
  31.     {
  32.         _listenSock = socket(AF_INET, SOCK_STREAM, 0);
  33.         if(_listenSock < 0)
  34.         {
  35.             LOG(FATAL, "Socket Error");
  36.             exit(1);
  37.         }
  38.         // 设置端口复用
  39.         int opt = 1;
  40.         setsockopt(_listenSock, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
  41.         LOG(INFO, "Create Listen Socket ... Success");
  42.     }
  43.     void Bind()
  44.     {
  45.         struct sockaddr_in local;
  46.         memset(&local, 0, sizeof(local));
  47.         local.sin_family = AF_INET;
  48.         local.sin_addr.s_addr = INADDR_ANY;
  49.         local.sin_port = htons(_port);
  50.         if(bind(_listenSock, (struct sockaddr*)&local, sizeof(local)) < 0)
  51.         {
  52.             LOG(FATAL, "Bind Error");
  53.             exit(2);
  54.         }
  55.         LOG(INFO, "Bind Socket ... Success");
  56.     }
  57.     void Listen()
  58.     {
  59.         if(listen(_listenSock, BACKLOG) < 0)
  60.         {
  61.             LOG(FATAL, "Listen Error");
  62.             exit(3);
  63.         }
  64.         LOG(INFO, "Listen Socket ... Success");
  65.     }
  66.     int Sock()
  67.     {
  68.         return _listenSock;
  69.     }
  70.     ~TcpServer()
  71.     {
  72.         if(_listenSock >= 0)
  73.         {
  74.             close(_listenSock);
  75.         }
  76.     }
  77. private:
  78.     TcpServer(uint16_t port)
  79.         : _port(port)
  80.         , _listenSock(-1)
  81.     {}
  82.     TcpServer(const TcpServer&) = delete;
  83. private:
  84.     uint16_t _port;
  85.     int _listenSock;
  86.     static TcpServer* svr;
  87. };
  88. TcpServer* TcpServer::svr = nullptr;
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

写过一篇

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表