我正在使用pthread在C++的Linux上制作Web服务器。我用valgrind测试了它的泄漏和内存问题-都已修复。我用helgrind测试了它的线程问题-全部修复。我正在尝试stress test。用Helgrind运行亵渎时我遇到问题

valgrind --tool=helgrind ./chats

它只是在随机的地方死于文本“Killed”,就像我用kill -9杀死它一样。我有时从helgrind那里获得的唯一报告是,该程序存在,同时还持有一些锁,这在被杀死时很正常。

检查泄漏时:
valgrind  --leak-check=full ./chats

它更稳定,但我设法通过数百个并发连接使其一次消失。

我尝试单独运行程序,根本无法使其崩溃。我尝试了250个并发连接。每个线程延迟100毫秒,以使同时进行多个连接变得更容易。没有崩溃。

在所有情况下,线程和连接都不会超过10,即使有2个连接,它也崩溃,但绝不会同时只有1个连接(包括主线程和1个辅助线程的总数为3)。
  • 是否有可能仅在使用
    helgrind还是仅仅helgrind使其更可能显示?
  • 程序被内核杀死的原因是什么?分配过多的内存,太多的文件描述符?

  • 我进行了更多测试,发现它仅在客户端超时并关闭连接时消失。因此,这是检测客户端关闭套接字的代码:
    void *TcpClient::run(){
      int ret;
      struct timeval tv;
      char * buff = (char *)malloc(10001);
      int br;
    
      colorPrintf(TC_GREEN, "new client starting: %d\n", sockFd);
      while(isRunning()){
        tv.tv_sec = 0;
        tv.tv_usec = 500*1000;
        FD_SET(sockFd, &readFds);
        ret = select(sockFd+1, &readFds, NULL, NULL, &tv);
        if(ret < 0){
          //select error
          continue;
        }else if(ret == 0){
          // no data to read
          continue;
        }
        br = read(sockFd, buff, 10000);
        buff[br] = 0;
    
        if (br == 0){
        // client disconnected;
          setRunning(false);
          break;
        }
    
        if (reader != NULL){
          reader->tcpRead(this, std::string(buff, br));
        }else{
          readBuffer.append(buff, br);
        }
        //printf("received: %s\n", buff);
    
      }
      free(buff);
    
      sendFeedback((void *)1);
      colorPrintf(TC_RED, "closing client socket: %d\n", sockFd);
      ::close(sockFd);
      sockFd = -1;
    
      return NULL;
    }
    // this method writes to socket
    bool TcpClient::write(std::string data){
      int bw;
      int dataLen = data.length();
    
      bw = ::write(sockFd, data.data(), dataLen);
      if (bw != dataLen){
        return false; // I don't close the socket in this case, maybe I should
      }
      return true;
    }
    

    P.S.线程是:
  • 主线程。此处接受连接。
  • 一个帮助程序线程,它监听信号并发送信号。它将停止接收该应用程序的信号,并手动轮询信号队列。原因是因为使用线程时很难处理信号。我在stackoverflow中发现了这项技术,并且在其他项目中也可以正常工作。
  • 客户端连接线程

  • 完整的代码很大,但是如果有人感兴趣,我可以发布代码块。

    更新:

    我仅用一个连接就触发了该问题。这一切都发生在客户端线程中。这是我的工作:
  • 我读取/解析标题。我在写入之前设置了延迟,以便客户端可以超时(这会导致问题)。
  • 客户端超时并离开(可能关闭套接字)
  • 我写回头
  • 我写回html代码。

  • 这是我回信的方式
      bw = ::write(sockFd, data.data(), dataLen);
      // bw is = dataLen = 108 when writing the headers
      //then secondary write for HTML kills the program. there is a message before and after write()
      bw = ::write(sockFd, data.data(), dataLen); // doesn't go past this point second time
    

    更新2:知道了:)

    gdb sais:
    Program received signal SIGPIPE, Broken pipe.
    [Switching to Thread 0x41401940 (LWP 10554)]
    0x0000003ac2e0d89b in write () from /lib64/libpthread.so.0
    

    问题1:我应该怎么做才能使收到此信号无效。
    问题2:如何知道写入时远端已断开连接。选择读取时返回有数据,但读取的数据为0。写操作如何?

    最佳答案

    好吧,我只需要处理SIGPIPE信号并写返回-1->我关闭套接字并优雅地退出线程。奇迹般有效。

    我猜最简单的方法是将SIGPIPE的信号处理程序设置为SIG_IGN:

    signal(SIGPIPE, SIG_IGN);
    

    请注意,首次写入成功,并且没有终止程序。如果您有类似的问题,请检查是否要编写一次或多次。如果您不熟悉gdb,请执行以下操作:
    gdb ./your-program
    > run
    

    并且gdb会告诉您有关信号和sigfaults的所有信息。

    09-06 03:07