标题说明了一切,我认为将对象存储在对象容器中将允许简单的跨线程类成员访问,因为它实际上将对象存储在由对象容器管理的内存空间中,在此案例一张地图。这是不正确的?因为发生了以下情况;
客户类:
class Client
{
public:
Client(std::string clientID,SOCKET sock,bool quit);
boost::thread_group *group;
/*CUT*/
std::string clientID;
std::deque<std::string> snapShotsQueue;
SOCKET sock;
bool quit;
void sendMessage(std::string);
void threadSend(Client *client);
void checksnapshots();
/*CUT*/
};
地图
typedef std::map<std::string, Client> clientMap;
clientMap clientmap;
(1)在main()
中创建的boost线程void alwaysWatching()
{
while(1)
{
/*CUT*/
/* When something that needs to be communcated happens, a message will be formed and stored in the string "thaString" and sent to, in this case, all clients*/
for (clientMap::iterator it2 = clientmap.begin(); it2 != clientmap.end(); ++it2)
{
it2->second.snapShotsQueue.push_back(thaString); //Add to client's deque
//Check how many items are in deque
std::cout << "There are now ";
it2->second.checksnapshots();
std::cout << "Snapshots waiting according to outside watcher" << std::endl;
}
/*CUT*/
}
}
(2)创建客户端对象并将其添加到地图
DWORD WINAPI ClientThread(LPVOID lpParam)
{
SOCKET sock=(SOCKET)lpParam;
/*CUT*/
std::string clientID = "";
std::stringstream ss;
ss << lpParam; //Socket = clientID
clientID = ss.str();
Client client(clientID,sock,false); //Create object for this client
while(1) //This thread is constantly waiting for messages sent by the client
{
/*CUT*/
//Add clientID to map of clients
if(clientAdded == false)
{
/*CUT*/
clientmap.insert(std::pair<std::string,Client>(clientID,client));
clientAdded = true;
/*CUT*/
}
/*CUT*/
return 0;
}
(3)将双端队列中的所有消息发送到客户端的线程
//Struct used to create the thread that will keep on sending messages in deque to the client
struct messageSender
{
messageSender(Client *client) : client(client) { }
void operator()()
{
client->threadSend(client);
}
Client *client;
};
//Client constructor
Client::Client(std::string clientIDs,SOCKET socks,bool quits)
{
/*CUT*/
this->group = new boost::thread_group; //Create boost thread group (for later, possibly)
messageSender startit(this); //Prep new thread for sending snapshot updates
group->create_thread(startit); //Start new thread for snapshot updates
/*CUT*/
}
//The actual function that constantly loops through the deque
void Client::threadSend(Client *client)
{
/*CUT*/
while(1)
{
/*CUT*/
std::cout << "There are now ";
client->checksnapshots();
std::cout << "Snapshots waiting according to class thread queue processor" << std::endl;
/*CUT*/
unsigned int i;
for(i=0; i < client->snapShotsQueue.size(); i++)
{
std::string theString;
theString = client->snapShotsQueue.front(); // this gets the front of the deque
client->snapShotsQueue.pop_front(); // this removes the front of the deque
std::cout << "sending: " << theString << std::endl;
client->sendMessage(theString);
}
}
}
正如您所看到的,我添加了一段代码,用于计算类外部线程以及类内部的双端队列。它们都报告不同的计数器,并且不会发送来自该类外部线程的消息。
所以看起来观察者线程(1)有自己的Client对象实例,即使它存储在地图内部。或者朝那个方向发展。
我可能在指针方面做错了。有什么想法吗?
答案 0 :(得分:4)
您正在将Client
复制到地图中,是的,但是无论何时读出它们,您都会通过复制地图中的Client
隐式创建新的std::map<std::string, Client *>
。新副本将具有单独的快照队列。
您可能希望使用std::map<std::string *, Client *>
或Client
,并使用new Client(...)
(以及相应的delete
s)分配您的所有Client
。然后,对于您放入地图的每个客户端,可能只有一个{{1}}实例,其中包含多个指针副本。
答案 1 :(得分:1)
根据您的问题,您可能真的想在地图中存储指针而不是像Ruakh建议的那样 - 只需要小心或者使用shared_ptrs。
或者,如果您将对象存储在地图本身中就可以了,您可以通过引用访问它 - 在这种情况下,不会创建副本,但您不必处理内存分配:
简单示例:
std::map<std::string, int> m;
m["Test"] = 5;
int& val = m["Test"];
int& val2 = m["Test"];
val = 10;
printf("%d\n", val2); // prints 10, not 5.