gpt4 book ai didi

c++ - 在多线程iocp服务器中将连接用户列表发送给新连接的用户

转载 作者:太空宇宙 更新时间:2023-11-04 05:26:23 25 4
gpt4 key购买 nike

我需要一些建议如何正确发送已连接用户的双向链表。到目前为止,有关我的代码和方法的一些基本信息:

我将有关所有连接用户的信息保存在双向链表中,该链表在线程之间共享。我将列表的头部存储在全局变量中:*PPER_user g_usersList,用户结构如下:

typedef struct _user {
char id;
char status;
struct _user *pCtxtBack;
struct _user *pCtxtForward;
} user, *PPER_user;

当新用户连接到服务器时,连接用户的数据从链表中收集并发送给他:

 WSABUF wsabuf; PPER_player pTemp1, pTemp2; unsigned int c=0;
.....
EnterCriticalSection(&g_CSuserslist);
pTemp1 = g_usersList;
while( pTemp1 ) {
pTemp2 = pTemp1->pCtxtBack;
wsabuf.buf[c++]=pTemp1->id; // fill buffer with data about all users
wsabuf.buf[c++]=pTemp1->status; //
pTemp1 = pTemp2;
};
WSASend(...,wsabuf,...);
LeaveCriticalSection(&g_CSuserslist);

但是关于上面代码的一些事情让我感到困惑:

  1. 链表被其他线程大量使用。连接的用户越多(例如 100,1000),在收集数据的整个过程中锁定列表的时间越长。我应该接受这一点还是找到更好的方法来做到这一点?

  2. 似乎当一个线程锁定列表而 while 循环遍历所有链式结构(用户)收集所有 id、status 时,当用户想要更改自己的 id 时,其他线程应该使用相同的 CriticalSection(&g_CSuserslist),状态等。但这可能会破坏性能。也许我应该更改我的应用程序的所有设计或其他什么?

如果您有任何见解,我们将不胜感激。提前致谢。

最佳答案

我在您的代码中(更普遍地在您的应用程序描述中)看到的唯一问题是保护 g_usersList 的关键部分的大小。规则是避免在关键部分进行任何耗时的操作

所以你必须保护:

  • 添加新用户
  • 在断开连接时删除用户
  • 拍摄列表的快照以供进一步处理

所有这些操作都只是内存操作,所以除非你在非常繁重的条件下进行,否则一切都应该没问题只要你将所有 IO 放在临界区之外 (1),因为它仅在用户连接/断开连接时发生。如果您将 WSASend 放在关键部分之外,一切都会正常进行,恕我直言,这就足够了。

根据评论编辑:

你的结构 user 相当小,我会说在 10 到 18 个有用字节之间(取决于指针大小 4 或 8 个字节),总共 24 个字节中的 12 个字节包括填充。对于 1000 个连接的用户,您只需复制少于 24k 字节的内存,并且只需测试下一个 user 是否为空(或者最多保持当前连接用户的数量以获得更简单的循环)。无论如何,维护这样的缓冲区也应该在临界区中完成。恕我直言,直到你有超过 1000 个用户(在 10k 到 100k 之间,但你可能会遇到其他问题......)一个简单的全局锁(就像你的关键部分)围绕 user 的整个双链表应该够了。但是所有这些都需要探测,因为它可能取决于硬件等外部因素......


太长了不要看讨论:

当您描述您的应用程序时,您仅在新用户连接时收集已连接用户的列表,因此每两次写入您只有一次完整读取(一次在连接时,一次在断开连接时):恕我直言,尝试这样做是没有用的实现读共享锁和写独占锁。如果您在连接和断开连接之间进行了多次读取,那将不是一回事,您应该尝试允许并发读取。

如果你真的觉得争用太重,因为你有非常多的连接用户和非常频繁的连接/断开,你可以尝试实现一个行级锁定。不是锁定整个列表,而是只锁定您正在处理的内容:顶部和第一个用于插入,当前记录加上前一个和下一个用于删除,当前和下一个在读取时。但是编写和测试会很困难,更耗时,因为你必须在读取列表时进行多次锁定/释放,并且你必须非常谨慎以避免出现死锁情况。所以我的建议是除非确实需要,否则不要这样做。


(1) 在您显示的代码中,WSASend(...,wsabuf,...); 临界区 应该在外面。改为写:

...
LeaveCriticalSection(&g_CSuserslist);
WSASend(...,wsabuf,...);

关于c++ - 在多线程iocp服务器中将连接用户列表发送给新连接的用户,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25773065/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com