में मुझे एक बहु-थ्रेडेड टीसीपी सर्वर में इंटरलॉक मॉनिटर.एट और मॉनीटर.पल्स के साथ समस्या हो रही है। मेरी मुद्दों प्रदर्शित करने के लिए, यहाँ अपने सर्वर कोड है:मॉनिटर.एट/पल्स रेस कंडीशन मल्टीथ्रेडेड सर्वर
public class Server
{
TcpListener listener;
Object sync;
IHandler handler;
bool running;
public Server(IHandler handler, int port)
{
this.handler = handler;
IPAddress address = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
listener = new TcpListener(address, port);
sync = new Object();
running = false;
}
public void Start()
{
Thread thread = new Thread(ThreadStart);
thread.Start();
}
public void Stop()
{
lock (sync)
{
listener.Stop();
running = false;
Monitor.Pulse(sync);
}
}
void ThreadStart()
{
if (!running)
{
listener.Start();
running = true;
lock (sync)
{
while (running)
{
try
{
listener.BeginAcceptTcpClient(new AsyncCallback(Accept), listener);
Monitor.Wait(sync); // Release lock and wait for a pulse
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
}
void Accept(IAsyncResult result)
{
// Let the server continue listening
lock (sync)
{
Monitor.Pulse(sync);
}
if (running)
{
TcpListener listener = (TcpListener)result.AsyncState;
using (TcpClient client = listener.EndAcceptTcpClient(result))
{
handler.Handle(client.GetStream());
}
}
}
}
यहाँ और मेरे मुवक्किल कोड है:
class Client
{
class EchoHandler : IHandler
{
public void Handle(Stream stream)
{
System.Console.Out.Write("Echo Handler: ");
StringBuilder sb = new StringBuilder();
byte[] buffer = new byte[1024];
int count = 0;
while ((count = stream.Read(buffer, 0, 1024)) > 0)
{
sb.Append(Encoding.ASCII.GetString(buffer, 0, count));
}
System.Console.Out.WriteLine(sb.ToString());
System.Console.Out.Flush();
}
}
static IPAddress localhost = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
public static int Main()
{
Server server1 = new Server(new EchoHandler(), 1000);
Server server2 = new Server(new EchoHandler(), 1001);
server1.Start();
server2.Start();
Console.WriteLine("Press return to test...");
Console.ReadLine();
// Note interleaved ports
SendMsg("Test1", 1000);
SendMsg("Test2", 1001);
SendMsg("Test3", 1000);
SendMsg("Test4", 1001);
SendMsg("Test5", 1000);
SendMsg("Test6", 1001);
SendMsg("Test7", 1000);
Console.WriteLine("Press return to terminate...");
Console.ReadLine();
server1.Stop();
server2.Stop();
return 0;
}
public static void SendMsg(String msg, int port)
{
IPEndPoint endPoint = new IPEndPoint(localhost, port);
byte[] buffer = Encoding.ASCII.GetBytes(msg);
using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
s.Connect(endPoint);
s.Send(buffer);
}
}
}
ग्राहक सात संदेश भेजता है, लेकिन सर्वर ने केवल चार प्रिंट:
Press return to test... Press return to terminate... Echo Handler: Test1 Echo Handler: Test3 Echo Handler: Test2 Echo Handler: Test4
मुझे संदेह है कि को Wait
से पहले होने पर मॉनीटर Pulse
(सर्वर की Accept
विधि में) को अनुमति देकर भ्रमित हो रहा है (i ThreadStart
विधि), भले ही ThreadStart
को sync
ऑब्जेक्ट पर लॉक होना चाहिए, जब तक कि यह Monitor.Wait()
पर कॉल न करे, और फिर Accept
विधि लॉक प्राप्त कर सकती है और Pulse
भेज सकती है। आप सर्वर के Stop()
विधि में इन दो पंक्तियों बाहर टिप्पणी करते हैं:
//listener.Stop();
//running = false;
शेष संदेश दिखाई देते हैं जब सर्वर के Stop()
विधि कहा जाता है (यदि सर्वर के sync
वस्तु जागने यह शेष भेजे गए संदेशों प्रेषण करने के लिए कारण बनता है)। ऐसा लगता है कि यह केवल ThreadStart
और Accept
विधियों के बीच दौड़ की स्थिति में हो सकता है, लेकिन sync
ऑब्जेक्ट के आसपास लॉक को इसे रोकना चाहिए।
कोई विचार?
बहुत धन्यवाद, साइमन।
ps। ध्यान दें कि मुझे पता है कि उत्पादन आउट-ऑफ-ऑर्डर इत्यादि दिखाई देता है, मैं विशेष रूप से ताले और मॉनीटर के बीच दौड़ की स्थिति के बारे में पूछ रहा हूं। चीयर्स, एसएच।
धन्यवाद मैट। मैंने माना कि BeginAcceptTcpClient हमेशा एक अलग धागे पर चला गया और इस प्रकार मैं सिंक ऑब्जेक्ट को एक महत्वपूर्ण खंड के रूप में उपयोग कर सकता था। आप जगह पर थे और सिग्नल जाने का रास्ता हैं। एक बार फिर धन्यवाद। एसएच –