试图创建一个线程来向套接字发送消息。遇到与线程构造函数有关的 2 个错误

Posted

技术标签:

【中文标题】试图创建一个线程来向套接字发送消息。遇到与线程构造函数有关的 2 个错误【英文标题】:Trying to create a thread to send a message to a socket. Getting 2 errors having to do with thread constructor 【发布时间】:2019-11-22 22:31:51 【问题描述】:

我正在尝试创建一个线程以向打开的套接字发送消息。我收到 2 个特定错误。

E0289: 没有构造函数“std::thread::thread”的实例与参数列表匹配。

C2661: 'std::thread::thread' 没有重载函数需要 2 个参数**

我找到了关于此的类似帖子,但仍然无法完全弄清楚是否真的可以使用一些澄清。

#include <WS2tcpip.h>
#include <string>
#include <thread>

using namespace std;

#pragma comment (lib, "ws2_32.lib")

void SendMessage(string message)

    WSAData data;
    WORD version = MAKEWORD(2, 2);
    int wsOk = WSAStartup(version, &data);
    if (wsOk != 0)
    
        cout << "Failed, Error Code: " << WSAGetLastError() << endl;
    

    sockaddr_in user;
    user.sin_family = AF_INET;
    user.sin_port = htons(3514);
    inet_pton(AF_INET, "127.0.0.1", &user.sin_addr);

    SOCKET out = socket(AF_INET, SOCK_DGRAM, 0);

    int sendMsg = sendto(out, message.c_str(), message.size() + 1, 0, (sockaddr*)&user, sizeof(user));

    if (sendMsg == SOCKET_ERROR)
    
        cout << "Failed, Error: " << WSAGetLastError() << endl;
    

    closesocket(out);
    WSACleanup();


int main()

    string message = "";
    cout << "Enter a message to send: ";
    cin >> message;

    thread sendtoSocket (SendMessage, message);

    sendtoSocket.join();

    system("pause");
    return 0;

【问题讨论】:

不相关:我不确定每次通话时给WSAStartupWSACleanup 是否是个好主意。您可能只想在main 中执行此操作一次。如果没有,请put it in an RAII wrapper,这样它无论如何都会被清理干净。 我不是VS专家,但是好像没有启用C++11 【参考方案1】:

Windows has a SendMessage macro 根据是否启用 unicode 在SendMessageASendMessageW 函数之间进行透明切换。这个宏替换会影响您的 SendMessage 函数。

你可以添加

#undef SendMessage

之后的任何地方

#include <WS2tcpip.h>

但这可能会在以后引起问题。我认为您最好将 SendMessage 函数的名称更改为不会发生冲突的名称。

TL;DR 版本

为什么会出现这个问题?模棱两可。让我们将其分解为MCVE。

#include <WS2tcpip.h>
#include <string>
#include <thread>
#include <iostream>

using namespace std;

void SendMessage(string /*message*/)



int main()

    string message = "Test";

    thread sendtoSocket (SendMessage, message);

    sendtoSocket.join();

经过预处理器后,程序看起来像

void SendMessageW(string /*message*/)



int main()

    string message = "Test";

    thread sendtoSocket (SendMessageW, message);

    sendtoSocket.join();

编译器现在必须弄清楚它必须为thread sendtoSocket (SendMessageW, message);、询问器或Win32 API 函数调用哪个SendMessageW 重载,但它不能。这会导致编译器寻找额外的线程构造函数并产生误导性诊断。

看看这是怎么回事,我们需要一个更简单的 MCVE,其中模板化函数没有重载

void A(int )



void A(double )



template<typename FUNC, typename... ARGS>
  void test(FUNC&& func, ARGS&&... args)
  
    func(args...);
  


int main()

    int message = 10;
    test(A, message);

这会产生有意义的诊断:

错误 C2672:“测试”:找不到匹配的重载函数

错误 C2783: 'void test(FUNC &&,ARGS &&...)': 无法推导出 'FUNC' 的模板参数

【讨论】:

谢谢,正是这个问题!我还修复了 WSAStartup 和 WSACleanup。 @Andy 很久以前我发现 strlen 函数有时出于性能原因被实现为宏。花了半天时间试图弄清楚为什么 int strlen; 会生成大约一页编译器错误,现在完全同意 Macros Are Evil 运动。 这怎么不会导致 OP 的 SendMessage 定义出现错误?它要么变得毫无意义,要么重新定义映射到的 API 函数。 MSVC 错误消息对我来说也没有任何意义。为什么它不抱怨类型不匹配,而不是给出没有重载接受两个参数的错误声明。 这是一个非常好的问题,@uneven_mark。我不确定为什么我们没有看到更多错误或歧义错误。我会制作一个预处理器文件,看看我能看到什么。 @uneven_mark 宏替换正是您所期望的,因此声明了 Andy 和 Microsoft 的 SendMessageW。这应该通过参数的差异来解决。一定是我在这里想念的其他东西。必须继续从事有偿工作,所以我暂时放弃了。

以上是关于试图创建一个线程来向套接字发送消息。遇到与线程构造函数有关的 2 个错误的主要内容,如果未能解决你的问题,请参考以下文章

从套接字接收线程中的消息

主线程与子线程之间相互通信(HandlerThread)

带有线程池服务器python的套接字

如何为pyserial读取运行线程

套接字:客户端读取消息时多线程不起作用

python多线程和套接字连接问题