[FIXED] So lassen Sie nur einen Thread einen kritischen Abschnitt ausführen, während die anderen Threads ohne Hängenbleiben verworfen werden

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. CompareExchangestellt die Atomarität sicher, sodass nur ein Thread den Wert der _runningVariablen 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)

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like