PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Friday, October 21, 2022

[FIXED] How to let only one thread to run a critical section while discarding the other threads without hang

 October 21, 2022     c#, multithreading, sockets     No comments   

Issue

I'm developing a windows service with .NET framework 4.0 and C#.

This service will open a socket to receive commands.

I have this socket listener class:

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);
    }
}

And this class to process the commands received through the socket:

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();
            }
    }
}

And, the CommandHandler:

class CommandHandler
{
    public static void ProcessCommand(string command, string connStringINICIC, string connStringTRZIC, byte codeLevel)
    {
        switch (command)
        {
            case "GetNewCodes<EOF>":
                CodesIncremental.GetNewCodes();
                break;
        }
    }
}

And CodesIncremental:

public class CodesIncremental
{
    public static bool GetNewCodes()
    {
        [ ... ]
    }
}

My problem is that I can receive GetNewCodes<EOF> command before the first one finish. So, I need to don't let GetNewCodes<EOF>runs if there is another GetNewCodes<EOF> running.

How can I don't let run CodesIncremental.GetNewCodes(); if this code its running in another thread?

I need something to discard the commands received while CodesIncremental.GetNewCodes(); is running.

In pseudo code:

If CodesIncremental.GetNewCodes(); is running do nothing.


Solution

This version does not block. CompareExchange ensures atomicity, so only one thread will swap the value of the _running variable, the rest of threads will just return inmediately.

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;
        }
    }
}

A difference than monitors or other synchronization methods, there is little contention on this method, and it is quite faster.



Answered By - vtortola
Answer Checked By - Dawn Plyler (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing