Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我应该锁定源代码的哪一部分?_C#_Tcp_Thread Safety_Locking - Fatal编程技术网

C# 我应该锁定源代码的哪一部分?

C# 我应该锁定源代码的哪一部分?,c#,tcp,thread-safety,locking,C#,Tcp,Thread Safety,Locking,以下是我的.net服务器的基本框架: 类服务器程序 { 静态字符串origClientID=string.Empty; 静态字符串reqClientID=string.Empty; 静态字符串stKey=string.Empty; 静态字符串stValue=string.Empty; 静态字典KeyValueDictionary; 静态字典ClientDictionary; 静态void Main(字符串[]参数) { Console.Title=“服务器”; Console.WriteLine

以下是我的.net服务器的基本框架:

类服务器程序
{
静态字符串origClientID=string.Empty;
静态字符串reqClientID=string.Empty;
静态字符串stKey=string.Empty;
静态字符串stValue=string.Empty;
静态字典KeyValueDictionary;
静态字典ClientDictionary;
静态void Main(字符串[]参数)
{
Console.Title=“服务器”;
Console.WriteLine(“服务器程序在地址[“+Constants.Server_IP+”:“+Constants.PORT_NO+”]”上启动);
KeyValueDictionary=新字典();
ClientDictionary=newdictionary();
字符串ipAddress=Constants.SERVER\u IP;
int portNo=常量。端口号;
IPAddress ip=IPAddress.Parse(IPAddress);
TcpListener侦听器=新的TcpListener(ip,端口号);
//在第二个线程中轮询客户端
线程线程=新线程(委托()
{
ServerProgram.PollingClientConns(侦听器);
});
thread.Start();
}
#区域捕获客户端连接
静态void pollingClientConns(TcpListener侦听器)
{
listener.Start();
尝试
{
bool-keepRunning=true;
同时(继续修剪)
{
ClientClass客户端=新的ClientClass(侦听器);
ClientDictionary.Add(client.ID,client);
线程线程=新线程(委托()
{
ServerProgram.ReadFromClient(客户端);
});
thread.Start();
}
}
捕获(例外情况除外)
{
var inner=ex.InnerException作为SocketException;
if(inner!=null&&inner.SocketErrorCode==SocketError.ConnectionReset)
控制台。写入线(“断开”);
其他的
控制台写入线(例如消息);
listener.Stop();
}
} 
#端区
静态void ReadFromClient(ClientClass客户端)
{
尝试
{
while(client.Tcp.Connected)
{
string str=client.Read();
Console.WriteLine(“[”+client.ID+“]表示:“+str”);
开关(str)
{
case Commands.AddKeyValue:
//...                        
打破
case Commands.ListKeys:
//...
打破
case Commands.UpdateValue:
//...
打破
案例命令。是:
//...
打破
}
}
}
抓住
{
client.Disconnect();
}
}
}
该计划的目标是:

  • 服务器保留一个键值的通用字典
  • 客户端可以在服务器中添加、更新和查看键值 类中使用了六个静态全局变量

    在访问之前,我应该锁定哪一个(我认为,字典不需要锁定)

    我应该锁定代码的哪一部分?我应该单独锁定开关盒,还是应该在静态void ReadFromClient(ClientClass client)中锁定整个while循环?

    我们可以肯定地说,您应该同步访问这两个字典-因为字典上的任何操作都不是线程安全的,你从多个线程中变异它们。一些类似的结构确实有线程安全说明,但没有
    字典

    是否需要同步字符串是。。。很棘手,尤其是因为你没有显示用法。对引用类型(
    string
    )的读写是原子的,字符串本身是不可变的(至少在正常使用时是如此)。但是,如果您执行的多个操作假定它们之间的值不变,则可能需要在组合操作期间进行同步。此外,请记住,您不能只
    锁定(stValue)
    ,因为当
    stValue
    更改时,两个不同的路径将针对不同的对象进行锁定。相反,您需要一个单独的字段,该字段仅用于锁定,并且独立于值

    最后,请注意,
    静态
    字段(当可以这样变化时)通常是一个坏主意。

    我们可以肯定地说,您应该同步访问两个字典-因为没有对字典的操作被记录为线程安全的,并且您是从多个线程对它们进行变异。一些类似的结构确实有线程安全说明,但没有
    字典

    是否需要同步字符串是。。。很棘手,尤其是因为你没有显示用法。对引用类型(
    string
    )的读写是原子的,字符串本身是不可变的(至少在正常使用时是如此)。但是,如果您执行的多个操作假定它们之间的值不变,则可能需要在组合操作期间进行同步。此外,请记住,您不能只
    锁定(stValue)
    ,因为当
    stValue
    更改时,两个不同的路径将针对不同的对象进行锁定。相反,您需要一个单独的字段,该字段仅用于锁定,并且独立于值


    最后,请注意,
    静态
    字段(如果是这样可变的)通常是一个坏主意。

    旁注:“每个客户端线程”通常不是一个好主意,除了客户端很少的普通服务器。旁注:您永远不会从
    客户端字典
    中删除,这听起来像是一个问题me@MarcGravell,
    附加说明:您从未从ClientDi中删除
    
    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();
            }
        }
    }