我在 2 个线程之间使用 ConcurrentQueue 可以吗?我想检查一下我不需要明确地“锁定”任何地方。特别是看看我在 COMMENTS 中的行,我会在这里丢弃一个数据包......
public class PacketCapturer
{
private static ConcurrentQueue<Packet> _packetQueue = new ConcurrentQueue<Packet>();
public PacketCapturer(IPHostEntry proxyDns, ref BackgroundWorker bw)
{
// start the background thread
var backgroundThread = new System.Threading.Thread(BackgroundThread);
backgroundThread.Start();
// Start Packet Capture with callback via PacketCapturerCallback
}
private void PacketCapturerCallback(Packet packet)
{
_packetQueue.Enqueue(packet);
}
private static void BackgroundThread()
{
while (!BackgroundThreadStop)
{
if (_packetQueue.Count == 0) Thread.Sleep(250);
else
{
ConcurrentQueue<Packet> ourQueue;
ourQueue = _packetQueue; // COULD I DROP A PACKET BETWEEN HERE
_packetQueue = new ConcurrentQueue<Packet>(); // AND HERE???
Console.WriteLine("BackgroundThread: ourQueue.Count is {0}", ourQueue.Count);
}
}
}
最佳答案
不,不行。首先,如果您在并发线程中像这样更改引用,则 _packetQueue 必须 标记为 volatile 以防止编译器和代码生成优化永远看不到更改。 _packetQueue 的缓存通常作为 Interlocked.CompareExchange 发生,但这对您的使用来说不是那么重要。
但更令人担忧的是在后台线程中像这样更改 packetQueue 实例的模式。这样做的目的是什么?它有一种可怕的代码气味...
已更新
我通常做的是:
生产者线程:
Producer () {
...
lock(_sharedQueue) {
_sharedQueue.Enqueue(something);
}
...
}
消费者线程:
consumer (...) {
...
var Something[] toProcess = null;
lock(_sharedQueue)
{
toProcess = _sharedQueue.Toarray();
_sharedQueue.Clear();
}
// Process here the toProcess array
...
}
这足以满足我的每一次使用。处理不会在锁定下发生,因此锁定最少。不需要花哨的 ConcurrentQueue,一个普通的旧 .Net 2.0 集合就足够了。通常我使用专用的锁定对象,而不是锁定实际的队列实例。
关于c# - 我在 2 个线程之间使用 ConcurrentQueue 可以吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3296413/