嗨,那里我在处理我的项目时感到头疼。
简短的摘要:
并发问题。锁没有发布
- 客户端/服务器应用程序(我是在服务器端)
- 多线程
- 保持活动分分秒秒与System.Timers.Timer在单独的线程
- 主要网络环路(读/写数据包到客户端/从客户端写数据包)
- 服务器在单独的线程上(此时无所谓)
我有一个处理所有客户端的ClientHandler类。 (Networker的是主循环) 客户端列表中,因为这实现:
public List<Client> ClientList { get; private set; }
每次我尝试访问客户端列表(读/写)我用...
lock(ClientList){}
lock(ClientHandler.ClientList){}
...依据如果我在ClientHandler内部或外部。
到目前为止,我没有使用任何锁,所以有一些并发问题。
但现在,当我使用/误用锁时,Keepalive遇到了一些问题。
如果一个客户端连接:
public bool AddClient(Client client)
{
lock (ClientList)
{
if (client == null || ClientList.Contains(client))
return false;
ClientList.Add(client);
return true;
}
}
每一秒我的定时器排入保持活动:
private void KeepAliveTimer_Elapsed(object sender, ElapsedEventArgs e)
{
KeepAliveTimer.Stop();
lock (ClientList)
{
if (ClientList.Count > 0)
{
foreach (Client client in ClientList)
{
lock (client)
{
client.PacketQueue.Enqueue(new KeepAlivePacket());
}
}
}
}
KeepAliveTimer.Start();
}
而且我现在的主循环:
private void Networker()
{
while (IsRunning)
{
lock (ClientHandler.ClientList)
{
if (ClientHandler.ClientList.Count > 0)
{
foreach (Client client in ClientHandler.ClientList)
{
// Check if client has data to read.
// Read for up to 10 msecs.
if (client.DataAvailable)
{
DateTime expiry = DateTime.Now.AddMilliseconds(10);
while (DateTime.Now <= expiry)
{
int id = client.ReadByte();
if (id == -1 || !PacketHandler.HandlePacket((byte)id, client, this))
{
ClientHandler.DisconnectClient(client);
continue;
}
}
}
// Check if client has data to write.
// Write for up to 10 msecs.
if (client.PacketQueue.Count > 0)
{
DateTime expiry = DateTime.Now.AddMilliseconds(10);
while (DateTime.Now <= expiry && client.PacketQueue.Count > 0)
{
IPacket packet = client.PacketQueue.Dequeue();
if (!packet.Write(client))
{
ClientHandler.DisconnectClient(client);
continue;
}
}
}
}
}
}
Thread.Sleep(1);
}
}
所有这些锁之前我的测试客户端每秒都会有一个KeepAlivePacket。
现在我只收到一次,因为第一个KeepAlivePacket KeepAliveTimer_Elapsed无法再访问该锁,因为它被其他线程永久锁定(用一些调试输出测试它)。
在提供的代码中是否有某些东西可能是疯子或者是否有其他东西我完全错了?
如果有人能让我摆脱这种痛苦,那将会很棒。
编辑(感谢约阿希姆伊萨克森):
我不知道这是否是唯一的错误,但有一件事我忘了是在主循环,以检查是否有可用的数据后,我读的第一个包。
这是第一个问题,因为我只发送一个数据包与我的TestClient和服务器卡在client.ReadByte因为事先没有检查。
if (client.DataAvailable)
{
DateTime expiry = DateTime.Now.AddMilliseconds(10);
while (DateTime.Now <= expiry && client.DataAvailable)
{
try
{
int id = client.ReadByte();
// do stuff...
}...
}
}
与论坛网站不同,我们不使用“谢谢”或“任何帮助表示赞赏”,或在[so]上签名。请参阅“[应该'嗨','谢谢',标语和致敬从帖子中删除?](http://meta.stackexchange.com/questions/2950/should-hi-thanks-taglines-and-salutations-be –
好吧,谢谢你会记住:) – TorbenJ
不知道你正在调用哪个'ReadByte',但我怀疑它会等待数据可用,如果没有,它会锁定,直到有,并且它永远不会释放锁 –