嗨,那裏我在處理我的項目時感到頭疼。
簡短的摘要:
併發問題。鎖沒有發佈
- 客戶端/服務器應用程序(我是在服務器端)
- 多線程
- 保持活動分分秒秒與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',但我懷疑它會等待數據可用,如果沒有,它會鎖定,直到有,並且它永遠不會釋放鎖 –