Ausgabe
Ich entwickle einen Windows-Dienst mit .NET Framework 4.0 und C#.
Dieser Dienst öffnet einen Socket, um Befehle zu empfangen.
Ich habe diese Socket-Listener-Klasse:
public class SocketListener
{
private System.Net.Sockets.TcpListener m_server;
public SQLServerSocketListener()
{
IPEndPoint ip = new IPEndPoint(IPAddress.Any, 5445);
m_server = new System.Net.Sockets.TcpListener(ip);
}
public void Start()
{
m_server.Start();
m_server.BeginAcceptTcpClient(new AsyncCallback(Callback), m_server);
}
public void Stop()
{
if (m_server != null)
m_server.Stop();
}
private void Callback(IAsyncResult ar)
{
if (!(m_server.Server.IsBound) ||
(m_server.Server == null))
return;
TcpClient client;
try
{
client = m_server.EndAcceptTcpClient(ar);
}
catch (ObjectDisposedException)
{
//Listener canceled
return;
}
DataHandler dataHandler = new DataHandler(client);
ThreadPool.QueueUserWorkItem(dataHandler.HandleClient, client);
m_server.BeginAcceptTcpClient(new AsyncCallback(Callback), m_server);
}
}
Und diese Klasse, um die über den Socket empfangenen Befehle zu verarbeiten:
class DataHandler
{
private bool m_disposed = false;
private TcpClient m_controlClient;
private IPEndPoint m_remoteEndPoint;
private string m_clientIP;
private NetworkStream m_controlStream;
private StreamReader m_controlReader;
public DataHandler(TcpClient client)
{
m_controlClient = client;
}
public void HandleClient(object obj)
{
m_remoteEndPoint = (IPEndPoint)m_controlClient.Client.RemoteEndPoint;
m_clientIP = m_remoteEndPoint.Address.ToString();
m_controlStream = m_controlClient.GetStream();
m_controlReader = new StreamReader(m_controlStream, true);
string line;
try
{
while (((line = m_controlReader.ReadLine()) != null) ||
(m_controlClient == null) ||
(!m_controlClient.Connected))
{
CommandHandler.ProcessCommand(line);
}
}
catch (Exception ex)
{
Console.WriteLine("CodeServerService.DataHandler error: {0}", ex.Message);
}
finally
{
Dispose();
}
}
}
Und der CommandHandler:
class CommandHandler
{
public static void ProcessCommand(string command, string connStringINICIC, string connStringTRZIC, byte codeLevel)
{
switch (command)
{
case "GetNewCodes<EOF>":
CodesIncremental.GetNewCodes();
break;
}
}
}
Und CodesIncremental
:
public class CodesIncremental
{
public static bool GetNewCodes()
{
[ ... ]
}
}
Mein Problem ist, dass ich GetNewCodes<EOF>
Befehle erhalten kann, bevor der erste fertig ist. Also muss ich nicht GetNewCodes<EOF>
laufen lassen, wenn es ein anderes GetNewCodes<EOF>
Rennen gibt.
Wie kann ich nicht ausführen lassen, CodesIncremental.GetNewCodes();
wenn dieser Code in einem anderen Thread ausgeführt wird?
CodesIncremental.GetNewCodes();
Ich brauche etwas, um die während der Ausführung empfangenen Befehle zu verwerfen .
Im Pseudocode:
Wenn CodesIncremental.GetNewCodes();
läuft nichts tun.
Lösung
Diese Version blockiert nicht. CompareExchange
stellt die Atomarität sicher, sodass nur ein Thread den Wert der _running
Variablen austauscht, der Rest der Threads wird einfach sofort zurückkehren.
public class CodesIncremental
{
static Int32 _running = 0;
public static bool GetNewCodes()
{
if (Interlocked.CompareExchange(ref _running, 1, 0) == 1)
return false;
try
{
// Do stuff...
return true;
}
finally
{
_running = 0;
}
}
}
Im Unterschied zu Monitoren oder anderen Synchronisierungsmethoden gibt es bei dieser Methode wenig Streit und sie ist ziemlich schneller.
Beantwortet von – vtortola
Antwort geprüft von – Jay B. (FixError Admin)