【发布时间】:2019-06-26 19:30:15
【问题描述】:
我正在尝试从多个线程访问一个方法,我不确定这是否是线程安全的。如果不是,那么确保其安全的最有效方法是什么?
我考虑了每个人的见解,我的最终产品如下所示,我还选择了对数据包本身调用回收。
我的数据包池类
using System.Collections.Generic;
namespace Networking
{
public class PacketPool
{
private Queue<Packet> pool = new Queue<Packet>();
private readonly object instance = new object();
public Packet CreatePacket(string method)
{
lock (instance)
return pool.Count == 0 ? new Packet() { Pool = this } :
pool.Dequeue();
}
public void Recycle(Packet packet)
{
lock(instance)
pool.Enqueue(packet);
}
}
}
数据包类
using System;
using System.Net;
namespace Networking
{
public class Packet
{
public Protocol Proto = Protocol.Sequenced;
public PacketFlags Flag = PacketFlags.None;
public Fragment Fragmented = Fragment.NotFragged;
public SendType SendType = SendType.Raw;
public EndPoint RemoteEp = new IPEndPoint(IPAddress.Any, 0);
public byte[] Buffer = new byte[512];
public int Count = 0;
public int Ptr = 8;
public int Bits { get; set; } = 0;
public ushort Id = 0;
public ushort Lead = 0;
public PacketPool Pool;
public void Recycle()
{
Bits = 0;
if (Buffer.Length > 512)
Array.Resize(ref Buffer, 512);
Count = 0;
Flag = PacketFlags.None;
Fragmented = Fragment.NotFragged;
Proto = Protocol.Sequenced;
Ptr = 8;
Lead = 0;
SendType = SendType.Raw;
Pool.Recycle(this);
}
}
}
希望上述解决方案能让生活更轻松。
【问题讨论】:
-
答案中指出了这一点,但为了进一步强调,
public Queue<Packet> pool = new Queue<Packet>(2000);违背了lock的目的。任何引用PacketPool的东西都可以在不获取该锁的情况下使项目入队或出队,因为Queue已暴露。这并不好,即使除了线程问题。如果您将其设为private,则确保只有类中的方法才能使项目入队或出队。 -
我现在将进行这些更改 :)
-
你为什么不使用
ConcurrentQueue<T>,这基本上会让你问题中的大部分代码立即消失...... ;-) -
好吧,我不知道残余影响是什么,但我猜它们与 ConcurrentQueue
本身没有直接关系。 (啊,刚刚注意到我之前的评论中有一个错误。我的意思是说“大部分锁定代码”,而不是“大部分代码”。这会很有趣如果 ConcurrentQueue 会神奇地替换那里的数据包实例重置......) -
第二个lock语句里面有很多行代码。他们都需要保护吗?您应该在尽可能短的时间内持有锁,以减少争用。
标签: c# multithreading thread-safety