我正在使用 pthreads 在 C++ 中的 linux 上创建一个 Web 服务器。我用 valgrind 测试了它的泄漏和内存问题 - 全部修复。我用 helgrind 测试了它的线程问题 - 全部修复。我正在尝试压力测试。当 probram 与 helgrind 一起运行时,我遇到了问题
valgrind --tool=helgrind ./chats
它只是在带有“已杀死”文本的随机位置上死亡,就像我用 . 杀死它时一样kill -9
。我有时从 hlgrind 得到的唯一报告是程序存在时仍然持有一些锁,这在被杀死时是正常的。
检查泄漏时:
valgrind --leak-check=full ./chats
它更稳定,但我设法让它在数百个并发连接的情况下死掉一次。
我尝试单独运行程序,根本无法让它崩溃。我尝试了多达 250 个并发连接。每个线程延迟 100 毫秒,以便更轻松地同时拥有多个连接。没有崩溃。
在所有情况下,线程和连接都不会超过 10,即使有 2 个连接,我也看到它崩溃,但绝不会同时只有一个连接(包括主线程和一个辅助线程,总共 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;
}
PS线程是:
- 主线程。这里接受连接。
- 一个监听信号并发送信号的辅助线程。它停止应用程序的信号接收并手动轮询信号队列。原因是使用线程时很难处理信号。我在 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 说:
Program received signal SIGPIPE, Broken pipe.
[Switching to Thread 0x41401940 (LWP 10554)]
0x0000003ac2e0d89b in write () from /lib64/libpthread.so.0
问题1:我应该怎么做才能使接收到这个信号无效。问题2:如何知道远程端在写入时断开连接。读取时选择返回有数据但读取的数据为0。写入怎么样?