【发布时间】:2020-12-14 18:25:08
【问题描述】:
感谢您的宝贵时间。
我想要完成什么? 我正在尝试利用线程来加速我的程序。经过一些分析后,我发现我的大部分程序时间(图形应用程序)都用于检查我的套接字状态。在尝试减少脂肪并降低到每个周期
有什么问题? 我无法理解线程和对象,我玩了一些运行良好的教科书示例并将本地函数与运行良好的线程相结合。试图将其转移到我自己的代码中已经证明超出了我的能力。
我尝试了什么? 我试图寻找智能指针来在堆上分配我的 UDPSocket 对象,希望所有线程都可以访问堆内存。出于同样的原因,我尝试了旧的新和删除。我尝试将我的 UDPSockets 包装在另一个对象中,并让整个对象在另一个线程上启动。
总结 可以肯定的是,我对线程的理解存在很大的漏洞,我将不胜感激这个特定问题的解决方案,但也可以链接到任何好的文章、教程、视频等这可能有助于加深我的理解。也许我只需要重新检查我的整个 UDPSocket 类?非常欢迎您的建议。
我将在下面发布我的示例,请注意,为了便于阅读,我已经删除了所有错误检查等。
#pragma once
#define WIN32_MEAN_AND_LEAN
#include <WS2tcpip.h>
#include <iostream>
#include <memory>
#include <thread>
#pragma comment(lib, "ws2_32.lib")
class UDPServer
{
public:
UDPServer(unsigned short port_in)
:
port(port_in)
{
// Startup Winsock
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOk = WSAStartup(version, &data);
//Bind socket to port, Any Address
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
//Hint structure
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = ADDR_ANY;
serverHint.sin_family = AF_INET;
serverHint.sin_port = htons(port);
bind(s, (sockaddr*)&serverHint, sizeof(serverHint));
}
~UDPServer()
{
closesocket(s);
WSACleanup();
}
bool Recieve()
{
ZeroMemory(&client, clientLength);
if (dataAvailable(s))
{
ZeroMemory(messageBuffer, bufferSize);
int bytesIn = recvfrom(s, messageBuffer, bufferSize, 0, (sockaddr*)&client, &clientLength);
char clientIP[bufferSize];
ZeroMemory(clientIP, bufferSize);
inet_ntop(AF_INET, &client.sin_addr, clientIP, 256);
return true;
}
return false;
}
std::string GetNetworkMessage()
{
std::string message = messageBuffer;
return message;
}
private:
bool dataAvailable(int sock, int interval = 6000)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(sock, &fds);
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = interval;
return (select(sock + 1, &fds, 0, 0, &tv) == 1);
}
private:
SOCKET s;
sockaddr_in client;
int clientLength = sizeof(client);
static constexpr int bufferSize = 512;
unsigned short port;
char messageBuffer[bufferSize] = {};
};
int main()
{
//Create server object on the heap.
std::unique_ptr<UDPServer> udp = std::make_unique<UDPServer>(6000);
//Get some new threads mate.
std::thread theThread;
std::string oldString = "";
while (true)
{
//Problems...
theThread = std::thread{udp->Recieve()};
if (udp->GetNetworkMessage() != oldString)
{
//print out any changed data we find.
oldString = udp->GetNetworkMessage();
std::cout << oldString << std::endl;
}
}
}
【问题讨论】:
-
多线程的关键是确保您拥有的数据保持在有效状态。例如不在一个线程中编辑变量,而另一个线程读取它。如果你想加快你的程序,具体的分析会有所帮助,例如如果大部分处理发生在
ZeroMemory,您可以尝试避免不必要的分配和取消分配。如果您只想异步运行一个函数而没有太多开销,那么std::async是一个不错的选择。 -
不确定您的
UDPServer能否处理对Recieve的线程访问。 -
theThread = std::thread{udp->Recieve()};每次循环时都会创建一个新的线程对象。线程的制作成本相对较高,我会创建一个线程池,以便只创建一次线程。然后主线程(执行选择和读取)将从套接字读取数据并移交要由池中的线程处理的数据包,使其立即返回侦听套接字上的更多数据包。 -
@MartinYork,关于我的 UDPServer 能够处理对 Receive 的线程访问,您几乎可以肯定是正确的哈哈。你能给我指出任何好的资源来了解线程池吗?快速的谷歌有很多东西,但它似乎是一个巨大的蠕虫罐头,我希望它是一个可靠的来源。
标签: c++ windows multithreading winsock