C pthread_创建内存泄漏
我正在尝试编写一个非常基本的多线程TCP客户机-服务器系统代码,并已设法使主要功能正常工作,并解决了除一个以外的所有内存问题 当服务器关闭时,我将其设置为接收和处理SIGINT信号,该信号将关闭listen和connfd,并执行一些任意输出 问题是valgrind在退出时报告内存泄漏,它说是来自pthread_create,线程在退出时保持活动状态。泄漏的大小是当时每个连接用户的272字节 sig处理程序和main的代码如下:C pthread_创建内存泄漏,c,multithreading,sockets,tcp,memory-leaks,C,Multithreading,Sockets,Tcp,Memory Leaks,我正在尝试编写一个非常基本的多线程TCP客户机-服务器系统代码,并已设法使主要功能正常工作,并解决了除一个以外的所有内存问题 当服务器关闭时,我将其设置为接收和处理SIGINT信号,该信号将关闭listen和connfd,并执行一些任意输出 问题是valgrind在退出时报告内存泄漏,它说是来自pthread_create,线程在退出时保持活动状态。泄漏的大小是当时每个连接用户的272字节 sig处理程序和main的代码如下: struct timeval t1, t2; int connfd
struct timeval t1, t2;
int connfd = 0;
int listenfd = 0;
pthread_t sniffer_thread;
static void SIGhandler(int sig, siginfo_t *siginfo, void *context)
{
pthread_join(sniffer_thread, NULL);
shutdown(connfd, SHUT_RDWR);
shutdown(listenfd, SHUT_RDWR);
gettimeofday(&t2, NULL);
double totalSeconds = (double) (t2.tv_usec - t1.tv_usec) / 1000000 + (double) (t2.tv_sec - t1.tv_sec) ;
int seconds = ((int)totalSeconds % 60);
int minutes = ((int)totalSeconds % 3600) / 60;
int hours = ((int)totalSeconds % 86400) / 3600;
int days = ((int)totalSeconds % (86400 * 30)) / 86400;
printf("\n\nServer shutdown request received");
printf ("\nTotal server up time = %d days %d hours %d minutes and %d seconds\n\n",days, hours ,minutes , seconds);
close(connfd);
close(listenfd);
exit(EXIT_SUCCESS);
}
int main(void)
{
gettimeofday(&t1, NULL);
struct sigaction act;
memset(&act, '\0', sizeof(act));
// this is a pointer to a function
act.sa_sigaction = &SIGhandler;
// the SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGINT, &act, NULL) == -1) {
perror("sigaction");
exit(EXIT_FAILURE);
}
struct sockaddr_in serv_addr;
struct sockaddr_in client_addr;
socklen_t socksize = sizeof(struct sockaddr_in);
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(50001);
bind(listenfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
if (listen(listenfd, 10) == -1) {
perror("Failed to listen");
exit(EXIT_FAILURE);
}
// end socket setup
//Accept and incoming connection
puts("Waiting for incoming connections...");
while (1) {
printf("Waiting for a client to connect...\n\n");
connfd =
accept(listenfd, (struct sockaddr *) &client_addr, &socksize);
printf("\n\nConnection established with: %s\n", inet_ntoa(client_addr.sin_addr));
printf("%s is connected on socket: %d\n",inet_ntoa(client_addr.sin_addr),connfd);
// third parameter is a pointer to the thread function, fourth is its actual parameter
if (pthread_create
(&sniffer_thread, NULL, client_handler,
(void *) &connfd) < 0) {
perror("could not create thread");
exit(EXIT_FAILURE);
}
printf("Handler assigned\n\n");
}
// never reached...
exit(EXIT_SUCCESS);
} // end main()
我尝试了许多不同的方法,包括在完成时分离线程,但最终总是导致内存泄漏。偶尔会发生内存泄漏,即使客户端只连接了服务器,服务器也会结束,其他情况下,只有客户端连接并与服务器交互时才会发生内存泄漏。您需要在while循环结束之前加入连接,而不是在信号捕获功能中加入连接 我建议您仔细阅读本指南的最后几节,它们处理的代码中的一些问题是: 连接线程,使线程不会因为正在使用 穿线, 您的connfd可以被覆盖,因为它存在于同一文件中 跨不同线程的内存空间 将while循环调整为 仅在连接打开时运行将其更改为在 承兑交还
我去实现了建议,不幸的是272字节仍在丢失!我继续给了建议的教程一个完整的实现,甚至在sigint上也丢失了相同的272字节exit@DarylVaDazzleMcAllister,运行valgrind时,始终将其设置为忽略在系统/库函数中发现的问题链接教程有一些问题。1将大多数错误消息输出到stdout,而不是stderr 2在将套接字传递到free之前,未能在客户端处理程序代码中传递要关闭的套接字。3有一条关于调用pthread_join的注释,但从未实际调用该函数。4线程应调用pthread_exit,作为比返回更好的选择5未能检查listen 6的返回值提取IP地址注释的循环将使用第一个但实际使用最后一个注释cont:7“connection_handler”函数应循环,直到读取返回为0,表示客户机已断开连接,然后退出循环8此语句:new_sock=malloc1;没有分配足够的空间。它应该是:new_sock=malloc sizeof int;然后检查分配是否成功:如果!new_sock{perror malloc失败;pthread_exit NULL;}8调用listen`表示三个连接可以同时处于活动状态,因此sniffer_线程应该是一个3的数组,并进行相关更改,以便主线程可以在循环中调用pthread_join cont,因此,在所有线程都退出之前,它不会退出。您可以与我们共享客户端处理程序函数的代码吗?@Jorgomermamedra现在将其编辑为包含客户端处理程序。除了您特别询问的问题之外,代码中还有很多问题。也就是说,在pthread_detach之后,不检查套接字返回的值,调用exit而不清除,主线程不能使用pthread_join“choice”是8个字符,但“switch”只能处理单个“int”值,而不能处理字符串。等等,等等,等等,等等,等等,等等;这是一个非常糟糕的主意,只需将“选择”设置为6。注意:“choice”是一个数组,而不是指向数组的指针,因此:switch*choice{应该是:switch choice和“choice”应该是一个“int”或单个字符。为了便于阅读和理解:1始终缩进代码。在每个左大括号“{”之后缩进。在每个右大括号“{”之前缩进。}“。建议每个缩进级别为4个空格。通过一个空行为、if、else、while、do…while、switch、case、default设置两个单独的代码块。
// thread function - one instance of each for each connected client
void *client_handler(void *socket_desc)
{
pthread_detach(pthread_self());
//Get the socket descriptor
int connfd = *(int *) socket_desc;
send_conConfirm(connfd);
char choice[8];
do {
get_menu_choice(connfd,choice);
switch (*choice) {
case '1':
printf("Executing IP/ID return for socket: %d\n",connfd);
send_studentID(connfd);
break;
case '2':
printf("Executing server time return for socket: %d\n",connfd);
send_serverTime(connfd);
break;
case '3':
printf("Executing sys info return for socket: %d\n",connfd);
send_uname(connfd);
break;
case '4':
printf("Executing file list return for socket: %d\n",connfd);
send_filenames(connfd,choice);
break;
case '5':
send_filenames(connfd,choice);
break;
case '6':
printf("Disconection choice on socket: %d\n",connfd);
break;
default:
printf("Client on socket %d has been disconnected\n", connfd);
goto jump;
break;
}
} while (*choice != '6' );
jump: //jump for goto statement
shutdown(connfd, SHUT_RDWR);
close(connfd);
printf("Thread %lu exiting\n", (unsigned long) pthread_self());
return 0;
} // end client_handler()