锁定异步操作的替代方法

时间:2018-07-20 11:38:45

标签: c# async-await synchronization

你好,我有以下问题:

我有一个类Pool,其中包含Connection-s列表。Connectionsocket的包装。我不知何故需要创建{{ 1}},socket-它,将它包装到ConnectAsync中,然后返回给调用者。问题是我需要这个collection是线程安全的。
我特别需要当我创建新的ConnectionConnection调用Connection-s Pool方法时,该集合将是线程安全的。

我有Free以外的其他选择吗?到目前为止,我已经看过lock,但我不明白。

游泳池

SemaphoreSlim

连接

   internal partial class Pool    {
            public static Pool MakePool(UserSettings settings)
            {
                return new Pool(settings);
            }

            private List<Connection> liveConnections;

            private readonly object @lock = new object();

            public readonly UserSettings settings;

            public async  Task<Connection> ConnectAsync()
            {
                Connection readyConnection;
                lock(@lock)
                {
                    if (this.liveConnections == null)
                    {
                        this.liveConnections = new List<Connection>(this.settings.MIN);
                    }
                    readyConnection = this.liveConnections.FirstOrDefault(x => !x.IsUsed);
                    if (readyConnection == null)
                    {

                        readyConnection = await CreateConnectionAsync(settings);
                        this.liveConnections.Add(readyConnection);

                    }

                    return readyConnection;

                }
            }
            private async Task<Connection> CreateConnectionAsync(UserSettings settings)
            {
                //Socket initialization
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress address=IPAddress.Parse(settings.HOST_NAME);
                int port = settings.PORT;
                IPEndPoint point = new IPEndPoint(address, port);
                await socket.ConnectAsync(point);


                ConnectionSettings conSettings = new ConnectionSettings
                {
                    pool = this,
                    ConnectionID = GenerateID(),
                    socket = socket,
                };
                Connection con= Connection.CreateConnection(conSettings);
                return con;

            }
            //this gets called by the connection !!
            internal void Free(string ID)
            {
                lock (@lock)
                {
                    Connection con=this.liveConnections.Find(x => x.ID == ID);
                    con.IsUsed = false;
                }
            }
            private static string GenerateID()=>Guid.NewGuid().ToString();

            private Pool(UserSettings settings)
            {
                this.settings = settings;
            }

        }

连接设置

public class Connection :IDisposable
    {
        private PhysicalConnection rawConnection;

        internal  static Connection CreateConnection(ConnectionSettings settings)
        {
            Connection con = new Connection(settings);

            return new Connection(settings);
        }

        public readonly string ID;
        private readonly Pool parentPool;
        public bool IsUsed { get; internal set; }

        public void Dispose()
        {
            this.parentPool.Free(this.ID);
        }



        private Connection(ConnectionSettings settings)
        {
            this.ID = settings.ConnectionID;
            this.parentPool = settings.pool;
            this.rawConnection = new PhysicalConnection(settings.socket);

        }
    }

如您所见,class ConnectionSettings { public Pool pool; public string ConnectionID; public Socket socket; } 是在Pool构造函数中发送的,因此Connection可以在Connection被处置时通知Pool

2 个答案:

答案 0 :(得分:1)

看起来您甚至不需要将对CreateConnectionAsync的调用保持在锁内:

public async  Task<Connection> ConnectAsync()
{
   Connection readyConnection;
   lock(@lock)
   {
       if (this.liveConnections == null)
       {
           this.liveConnections = new List<Connection>(this.settings.MIN);
       }
       readyConnection = this.liveConnections.FirstOrDefault(x => !x.IsUsed);
   }
   if (readyConnection == null)
   {
       readyConnection = await CreateConnectionAsync(settings);
       lock(@lock)
       {
            this.liveConnections.Add(readyConnection);
       }
   }
   return readyConnection;
}

您的CreateConnectionAsync根本不使用liveConnections集合。至此,您已经完成了对集合的搜索,因此可以在新连接异步尝试连接到其端点时将其解锁。

答案 1 :(得分:0)

您可以使用一对ConcurrentBags,一个用于使用,一个用于未使用的连接。在构造函数中初始化它们,我认为您根本不需要任何锁。