【发布时间】:2018-12-20 18:14:17
【问题描述】:
我有一个应用程序需要下载可变的文件列表(基于用户的更改、更改的内容等)。该列表可以很短也可以很长(1000 个文件)。我启动 X 工作线程,并为每个要下载的线程列出一个列表。如果我运行 1 个线程,一切正常。如果我运行 >1 个线程,它“可能”在 __acrt_lock 中崩溃(但是我不这么称呼它)。问题出在winsock connect 调用上。如果我注释掉那个调用,它就可以工作(显然不会下载文件,但它不会崩溃)。
这曾经在旧的 v110 编译器链下工作。我已经升级到v141链,现在问题出现了。当然,我使用的是多线程库。
我在各个地方都有过早返回语句的“快捷方式”代码,并确定调用winsock函数“connect”的单行是问题所在。没有使用全局变量(只有线程的私有本地存储)。
bool Socket::connect(const char * adrs, int port) {
lastErrCode = 0;
myIP = adrs;
myPort = port;
if (inet_addr(adrs) == INADDR_NONE) {
getHostByName(adrs, myIP);
}
else {
myIP = adrs;
}
if ((me = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
lastErrCode = WSAGetLastError();
return (false);
}
SOCKADDR_IN sock;
sock.sin_family = PF_INET;
sock.sin_port = htons(port);
sock.sin_addr.s_addr = inet_addr(myIP.str());
return(false); //:DEBUG:
if (::connect(me, (SOCKADDR*)&sock, sizeof(SOCKADDR)) == SOCKET_ERROR) {
lastErrCode = WSAGetLastError();
closesocket(me);
me = INVALID_SOCKET;
return (false);
}
return (true);
}
【问题讨论】:
-
这个问题中没有任何东西可以证明“winsock函数connect是问题所在”。仅仅因为 C++ 程序在一个特定函数中崩溃并不意味着这就是错误所在。 C++ 不能以这种方式工作。错误可以在崩溃前执行的代码中的任何位置。这就是为什么stackoverflow.com 的help center 告诉您必须准备minimal reproducible example。如果没有任何人都可以编译、运行和重现问题的minimal reproducible example,那么任何人都不太可能为您提供帮助。
-
你能用调试版本重现这个吗?可能是一些很好的信息。除此之外,我不确定
gethostbyname是可重入的。等等...这不是我习惯的gethostbyname。什么都没有给你。 minimal reproducible example,请。 -
有人因拼写错误投票关闭。不管是谁做的,你能把提问者和我扔到一块骨头上,让我们看看错字吗?我没看到。
-
gethostbyname()确实是不可重入的。它返回一个指向静态hostent结构的指针,如果gethostbyname()被多个线程同时调用,则不能保证该结构是安全的(但在WinSock 的情况下,它是安全的,因为该结构是在TLS 内存)。这是gethostbyname()被弃用而支持getaddrinfo()的众多原因之一,无论如何你都应该使用它。 -
谢谢大家。我解决了,请看下面的答案...
标签: c++ multithreading winsock2