你好,我有以下问题:
我有一个类Pool
,其中包含Connection
-s列表。Connection
是socket
的包装。我不知何故需要创建{{ 1}},socket
-它,将它包装到ConnectAsync
中,然后返回给调用者。问题是我需要这个collection是线程安全的。
我特别需要当我创建新的Connection
或Connection
调用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
!
答案 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,一个用于使用,一个用于未使用的连接。在构造函数中初始化它们,我认为您根本不需要任何锁。