valgrind / helgrind在压力测试中被杀死

时间:2013-11-04 14:46:27

标签: c++ linux multithreading tcp valgrind

我正在使用pthreads在C ++上使用Linux创建一个Web服务器。我用valgrind测试了泄漏和内存问题 - 所有修复。我用helgrind测试了线程问题 - 所有修复。我正在尝试stress test。当使用helgrind

运行probram时,我遇到了问题
valgrind --tool=helgrind ./chats

它只是在随机地方死亡,文字“被杀”,就像用kill -9杀死它时一样。我有时从helgrind获得的唯一报告是程序存在时仍保留一些锁,这在被杀时是正常的。

检查泄漏时:

valgrind  --leak-check=full ./chats

它更稳定,但我设法让它在几百个并发连接中死掉一次。

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

在所有情况下,线程和连接都不会超过10并且我看到即使有2个连接它也会崩溃,但是从来没有同时只有一个连接(包括主线程和一个帮助线程总共3个)

  1. 问题是否可能仅在运行时发生 helgrind或者只是helgrind使它更有可能显示?
  2. 程序被杀死的原因是什么(通过内核?)分配太多内存,文件描述符太多了?
  3. 我测试了一点,我发现它只会在客户端超时并关闭连接时死掉。所以这里是检测客户端关闭套接字的代码:

    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。主题是:

    1. 主线程。这里接受了连接。
    2. 一个帮助线程,它监听信号并发送信号。它会停止应用程序的信号接收并手动轮询信号队列。原因是因为使用线程时很难处理信号。我在stackoverflow中找到了这种技术,并且它在其他项目中的工作状态非常好。
    3. 客户端连接线程
    4. 完整的代码非常大,但如果有人感兴趣,我可以发布块。

      更新

      我设法只用一个连接来触发问题。这一切都发生在客户端线程中。这就是我的工作:

      1. 我读取/解析标题。我在写入之前放置了延迟,因此客户端可以超时(导致问题)。
      2. 此处客户端超时和离开(可能关闭套接字)
      3. 我写回标题
      4. 我回复了html代码。
      5. 这是我回信的方式

          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.如何写?

1 个答案:

答案 0 :(得分:2)

好吧,我只需处理SIGPIPE信号并写入返回-1 - &gt;我关闭套接字并优雅地退出线程。像魅力一样。

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

signal(SIGPIPE, SIG_IGN);

请注意,第一次写入是成功的,并没有杀死该程序。如果您有类似的问题,请检查您是写一次还是多次。如果你不熟悉gdb,那么这是怎么做的:

gdb ./your-program
> run

和gdb会告诉你有关信号和sigfaults的所有信息。