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

标签 c++ linux multithreading tcp valgrind

我正在使用 pthreads 在 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 个连接也会崩溃,但绝不会同时只有一个连接(包括主线程和一个辅助线程总共 3 个) .

  1. 问题是否可能只在运行时发生 helgrind 或仅 helgrind 使其更有可能显示?
  2. 程序(被内核)杀死的原因是什么?分配太多内存,太多文件描述符?

我测试了一点,发现它只会在客户端超时并关闭连接时死掉。所以这里是检测客户端关闭套接字的代码:

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;
}

附言线程是:

  1. 主线程。此处接受连接。
  2. 一个辅助线程,用于监听信号和发送信号。它停止应用程序的信号接收并手动轮询信号队列。原因是因为使用线程时很难处理信号。我在 stackoverflow 中发现了这项技术,它在其他项目中也能正常工作。
  3. 客户端连接线程

完整的代码非常大,但如果有人感兴趣,我可以发布 block 。

更新:

我设法通过一个连接触发了问题。这一切都发生在客户端线程中。这就是我所做的:

  1. 我阅读/解析标题。我在写入之前延迟,以便客户端可以超时(这会导致问题)。
  2. 这里客户端超时并离开(可能关闭套接字)
  3. 我写回标题
  4. 我写回 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 说:

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 会告诉您有关信号和信号故障的所有信息。

关于c++ - valgrind/helgrind 在压力测试中被杀死,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19770250/

相关文章:

c++ - void 指针可以指向 lambda 函数吗?

c++ - 编译器错误初始化 std::array of structs with clang

python - vim:符号查找错误:/lib/x86_64-linux-gnu/libpython3.8.so.1.0: undefined symbol :XML_SetHashSalt

c++ - 对于 C++ MacOSX 应用程序,要使用什么线程库?

c++ - 确保 float 小于 double C++

c++ - #ifdef 无法按预期使用预编译 header

c - 在后台执行命令

linux - do while 循环示例

java - 多线程访问中的ConcurrentModificationException

c++ - 最多同步派生的析构函数