如何从线程中的不同模块调用函数?

how does one call a function from a diffrent module in a thread?

本文关键字:模块 调用 函数 线程      更新时间:2023-10-16

我正在尝试使用套接字创建一个多线程服务器。 每个用户都会打开一个新线程。 这个线程运行一个函数,该函数最终需要从不同的模块调用另一个函数,但是当它到达它应该调用的函数时,我总是收到运行时错误。 有什么想法吗?

void Server::accept()
{
// notice that we step out to the global namespace
// for the resolution of the function accept
// this accepts the client and create a specific socket from server to this client
SOCKET client_socket = ::accept(_serverSocket, NULL, NULL);
if (client_socket == INVALID_SOCKET)
throw std::exception(__FUNCTION__);
std::cout << "Client accepted. Server and client can speak" << std::endl;
// the function that handle the conversation with the client
std::thread lol(&Server::clientHandler, this, std::ref(client_socket));
lol.detach();
}

void Server::clientHandler(SOCKET clientSocket)
{
try
{
std::cout << "IM HERE";
int userMessageType = 0;
int sizeOfUserName = 0;
int totalUserLen = 0;
std::string loginReply = "";
std::set<std::string> ::iterator itr;
std::string allNames = "";
while (userMessageType != MT_CLIENT_EXIT)
{
char buffer[2048];
std::cout << "IM HERE";
buffer[2047] = 0;
std::cout << "IM HERE";
userMessageType = Helper::getMessageTypeCode(clientSocket); // code crashes here!!
std::cout << "ASDSAD";
std::cout << "CODE " << userMessageType << std::endl;
switch (userMessageType)
{
case MT_CLIENT_LOG_IN:
{
sizeOfUserName = Helper::getIntPartFromSocket(clientSocket, 2);
std::string user = Helper::getStringPartFromSocket(clientSocket, sizeOfUserName);
std::cout << user << std::endl;
loginReply += "1010000000";
for (itr = onlineUsers.begin(); itr != onlineUsers.end(); itr++)
{
totalUserLen = totalUserLen + (int)(((*itr).length()));
allNames += *itr;
allNames += "&";
std::cout << "n" << allNames << "n";
}
if (totalUserLen != 0)
{
std::cout << "ASD" << allNames.size();
allNames[allNames.size() - 1] = '';
std::cout << "ASD";
allNames = allNames.substr(0, allNames.size() - 1);
std::cout <<"n" << allNames << "qqq";
for (int i = 0; i < 5 - allNames.length(); i++)
{
}
loginReply += std::to_string(allNames.length());
std::cout << loginReply;
Helper::sendData(clientSocket, loginReply);
}
else
{
loginReply += "00000";
Helper::sendData(clientSocket, loginReply);
std::cout << "ASD";
}
onlineUsers.insert(user);
}
case MT_CLIENT_UPDATE:
{
std::string;
}
case MT_CLIENT_EXIT:
{
closesocket(clientSocket);
return;
}
}
}
closesocket(clientSocket); 
}
catch (const std::exception& e)
{
closesocket(clientSocket);
}

}

最小生殖示例: 助手:

#include "Helper.h"
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
using std::string;
// recieves the type code of the message from socket (3 bytes)
// and returns the code. if no message found in the socket returns 0 (which means the client disconnected)
int Helper::getMessageTypeCode(SOCKET sc)
{
char* s = getPartFromSocket(sc, 3);
std::string msg(s);
if (msg == "")
return 0;
int res = std::atoi(s);
delete s;
return  res;
}

void Helper::send_update_message_to_client(SOCKET sc, const string& file_content, const string& second_username, const string &all_users)
{
//TRACE("all users: %sn", all_users.c_str())
const string code = std::to_string(MT_SERVER_UPDATE);
const string current_file_size = getPaddedNumber(file_content.size(), 5);
const string username_size = getPaddedNumber(second_username.size(), 2);
const string all_users_size = getPaddedNumber(all_users.size(), 5);
const string res = code + current_file_size + file_content + username_size + second_username + all_users_size + all_users;
//TRACE("message: %sn", res.c_str());
sendData(sc, res);
}
// recieve data from socket according byteSize
// returns the data as int
int Helper::getIntPartFromSocket(SOCKET sc, int bytesNum)
{
char* s = getPartFromSocket(sc, bytesNum, 0);
return atoi(s);
}
// recieve data from socket according byteSize
// returns the data as string
string Helper::getStringPartFromSocket(SOCKET sc, int bytesNum)
{
char* s = getPartFromSocket(sc, bytesNum, 0);
string res(s);
return res;
}
// return string after padding zeros if necessary
string Helper::getPaddedNumber(int num, int digits)
{
std::ostringstream ostr;
ostr << std::setw(digits) << std::setfill('0') << num;
return ostr.str();
}
// recieve data from socket according byteSize
// this is private function
char* Helper::getPartFromSocket(SOCKET sc, int bytesNum)
{
return getPartFromSocket(sc, bytesNum, 0);
}
char* Helper::getPartFromSocket(SOCKET sc, int bytesNum, int flags)
{
if (bytesNum == 0)
{
return (char*)"";
}
char* data = new char[bytesNum + 1];
int res = recv(sc, data, bytesNum, flags);
if (res == INVALID_SOCKET)
{
std::string s = "Error while recieving from socket: ";
s += std::to_string(sc);
throw std::exception(s.c_str());
}
data[bytesNum] = 0;
return data;
}
// send data to socket
// this is private function
void Helper::sendData(SOCKET sc, std::string message)
{
const char* data = message.c_str();
if (send(sc, data, message.size(), 0) == INVALID_SOCKET)
{
throw std::exception("Error while sending message to client");
}
}
SOCKET

是整型的类型定义,因此您应该std::ref( client_socket )部分替换为client_socket

此外,对Server::clientHandler的线程访问也不会同步。这不是一个好的解决方案,但为了防止竞争条件,您可以执行以下操作。

void Server::clientHandler(SOCKET clientSocket)
{
static std::mutex thread_safe;
// Guarantees that only one thread proceeds at a time
std::lock_guard<std::mutex> lock { thread_safe };
....
....