c# - 我在 2 个线程之间使用 ConcurrentQueue 可以吗?

标签 c# .net multithreading concurrency

我在 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/

相关文章:

c# - C++/CLI 和 .NET 输出字符串参数

c# - 在静态构造函数中初始化静态变量而不是直接赋值有什么好处

java - Java 8 中的 completableFuture 是否可以扩展到多核?

c++ - 无法获取 std::mutex 来正确保护线程访问

c# - 在 Visual Studio 上将文件添加为链接 - 调试与发布

c# - C# 中的正则表达式

.net - Dim v As String() 和 Dim v() As String 有什么区别?

c# - 在 ASP.NET 中的页面重定向之前执行长时间运行的方法

c# - Dispatcher.BeginInvoke : Cannot convert lambda to System. 委托(delegate)

c# - 基于异步注解执行C# Lambda表达式