Какую часть исходного кода я должен заблокировать? - PullRequest
0 голосов
/ 28 мая 2019

Ниже приведен базовый каркас моего .net-сервера:

Скелет C # -сервера

class ServerProgram
{
    static string origClientID = string.Empty;
    static string reqClientID = string.Empty;
    static string stKey = string.Empty;
    static string stValue = string.Empty;
    static Dictionary<string, KeyValue> KeyValueDictionary;
    static Dictionary<string, ClientClass> ClientDictionary;

    static void Main(string[] args)
    {
        Console.Title = "Server";
        Console.WriteLine("Server program started on address [" + Constants.SERVER_IP +":"+Constants.PORT_NO+"]");

        KeyValueDictionary = new Dictionary<string, KeyValue>();
        ClientDictionary = new Dictionary<string, ClientClass>();

        string ipAddress = Constants.SERVER_IP;
        int portNo = Constants.PORT_NO;

        IPAddress ip = IPAddress.Parse(ipAddress);            
        TcpListener listener = new TcpListener(ip, portNo);            

        // poll for clients in a 2nd thread
        Thread thread = new Thread(delegate()
        {
            ServerProgram.PollIncomingClientConns(listener);
        });

        thread.Start();
    }

    #region catching client connections
    static void PollIncomingClientConns(TcpListener listener)
    {
        listener.Start();

        try
        {
            bool keepRunning = true;

            while (keepRunning)
            {
                ClientClass client = new ClientClass(listener);

                ClientDictionary.Add(client.ID, client);

                Thread thread = new Thread(delegate()
                {
                    ServerProgram.ReadFromClient(client);
                });
                thread.Start();
            }
        }
        catch (Exception ex)
        {
            var inner = ex.InnerException as SocketException;
            if (inner != null && inner.SocketErrorCode == SocketError.ConnectionReset)
                Console.WriteLine("Disconnected");
            else
                Console.WriteLine(ex.Message);

            listener.Stop();
        }
    } 
    #endregion     

    static void ReadFromClient(ClientClass client)
    {
       try
        {
            while (client.Tcp.Connected)
            {
                string str = client.Read();
                Console.WriteLine("[" + client.ID + "] says: " + str);

                switch(str)
                {
                    case Commands.AddKeyValue:
                        //...                        
                        break;

                    case Commands.ListKeys:
                        //...
                        break;

                    case Commands.UpdateValue: 
                        //...
                        break;

                    case Commands.Yes:                            
                        //...
                        break;
                }
            }
        }
        catch
        {
            client.Disconnect();
        }
    }
}

Цель программы:

  1. На сервере хранится общий словарь значений ключей.
  2. клиенты могут добавлять, обновлять и просматривать значения ключей на сервере.

В классе используется шесть статических глобальных переменных.

Какие из них следует заблокировать перед доступом (я думаю, словарям не нужна блокировка)?

Какую часть кода я должен заблокировать?Должен ли я блокировать распределительные коробки индивидуально или блокировать весь цикл while в static void ReadFromClient(ClientClass client)?

1 Ответ

2 голосов
/ 28 мая 2019

Мы можем определенно сказать, что вы должны синхронизировать доступ к двум словарям - поскольку никакие операции над словарями не задокументированы как поточно-ориентированные, и вы мутируете их из нескольких потоков.Некоторые подобные структуры do имеют примечания по безопасности потоков, но не Dictionary<TKey,TValue>.

Нужно ли синхронизировать строки ... сложно, не в последнюю очередь потому, что вы не показываетеиспользование.Чтение и запись по ссылочным типам (string) являются атомарными, а сами строки неизменяемы (по крайней мере, при обычном использовании).Однако, если вы выполняете несколько операций, которые принимают между собой неизменное значение, вам может потребоваться синхронизация на время выполнения составных операций.Кроме того, имейте в виду, что вы не можете просто lock (stValue), потому что при изменении stValue два разных пути будут блокироваться для разных объектов .Вместо этого вам понадобится отдельное поле, которое существует только для блокировки и не зависит от значения.

Наконец, обратите внимание, что поля static - когда такие изменяемые - часто бываютплохая идея.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...