【问题标题】:How to use a mutex如何使用互斥锁
【发布时间】:2011-10-20 19:47:42
【问题描述】:

我有一个线程,通过 tcp 发送存储在 List 类型缓冲区中的数据。另一个线程正在写入缓冲区。由于我对 c# 不是很熟悉,我想知道如何正确使用 lock 或 Mutex。

这是我最终要使用的代码:

 while(buffer.isLocked()) 
 { 
    buffer.wait();
 }

  buffer.lockBuffer();
  buffer.add(tcpPacket);
  buffer.unlockBuffer();
  buffer.notify();

这是我当前的代码。我希望有人可以帮助我完成它。

public class Buffer
{
    private Mutex mutex; 
    private List<string> buffer; 
    private bool locked = false; 

    public Buffer()
    {
        mutex = new Mutex(false);
        buffer = new List<string>(); 
    }

    public bool isLocked()
    {
        return locked; 
    }

    public void lockBuffer()
    {
        if (!locked)
        {
            //...
           locked = true; 
        }
    }

    public void unlockBuffer()
    {
        if(locked)
        {
            mutex.ReleaseMutex();
            locked = false; 
        }
    }

    public void wait()
    {
        mutex.WaitOne();
    }

    public void notify()
    {
        //...
    }
}

【问题讨论】:

    标签: c# multithreading locking mutex


    【解决方案1】:

    如果你使用System.Collections.Concurrent.BlockingCollection会更好。它不需要外部同步。

    对于那些不使用 4.0 的人

    using System;
    using System.Collections.Generic;
    using System.Threading;
    
    namespace MyCollections
    {
        public class BlockingQueue<T> : IDisposable
        {
            Queue<T> _Queue = new Queue<T>();
            SemaphoreSlim _ItemsInQueue = null;
            SemaphoreSlim _FreeSlots = null;
            int _MaxItems = -1;
    
            public BlockingQueue(int maxItems=Int32.MaxValue)
            {
                _MaxItems = maxItems;
                _ItemsInQueue = new SemaphoreSlim(0, maxItems);
                _FreeSlots = new SemaphoreSlim(maxItems, maxItems);
            }
    
            public void Dispose()
            {
                if (_ItemsInQueue != null) _ItemsInQueue.Dispose();
                if (_FreeSlots != null) _FreeSlots.Dispose();
            }
    
            public int Count
            {
                get { return _ItemsInQueue.CurrentCount; }
            }
    
    
            public void Add(T item)
            {
                if(_MaxItems != Int32.MaxValue) _FreeSlots.Wait();
                lock (this)
                {
                    _Queue.Enqueue(item);
                    _ItemsInQueue.Release();
                }
            }
    
    
            public T Take()
            {
                T item = default(T);
                _ItemsInQueue.Wait();
                lock (this)
                {
                     item = _Queue.Dequeue();
                     if (_MaxItems != Int32.MaxValue)  _FreeSlots.Release();
                }
                return item;
            }
        }
    }
    

    【讨论】:

    • 他可能没有使用 .NET 4.0
    • 请注意,使用lock(this) 通常是一种不好的做法。如果一个外部类锁定了您的 BlockingQueue 怎么办?
    • 感谢代码!不过,我对 SemaphoreSlim 对象有一些问题。我认为这是因为我使用的是 .NET 3.5。你知道我该如何替换它们吗?
    • @AC-CII 这是个问题吗?然后声明一个要锁定的本地对象。这只是展示如何实现阻塞队列的示例。这会是否决票的理由吗?
    • @Pedro,将它们替换为 Semaphore ,将 Wait 替换为 WaitOne 并删除 Count 属性
    【解决方案2】:

    以下代码不是线程安全的。如果两个线程同时进入这个方法,那么两个线程都可能成功通过 if 条件。

    public void lockBuffer()
    {
        if (!locked)
        {
            //...
           locked = true; 
        }
    }
    

    您可能只想做这样的事情:

    lock (_sycnObject)
    {
      buffer.lockBuffer();
      buffer.add(tcpPacket);
      buffer.unlockBuffer();
      buffer.notify();
    }
    

    我不认为您正在做一些复杂的事情,需要的不仅仅是简单易用的锁定语句。

    【讨论】:

      【解决方案3】:

      我不会使用互斥锁,因为我想您没有处理多进程同步。锁非常好,实现起来也更简单:

      class Buffer
      {
          private readonly object syncObject = new object();
          private readonly List<string> buffer = new List<string>();
      
          public void AddPacket(string packet)
          {
              lock (syncObject)
              {
                  buffer.Add(packet);
              }
          }
      
          public void Notify()
          {
              // Do something, if needed lock again here
              // lock (syncObject)
              // {
              //     Notify Implementation
              // }
          }
      }
      

      用法显然是(根据您的要求):

      var myBuffer = new Buffer();
      myBuffer.Add("Hello, World!");
      myBuffer.Notify();
      

      【讨论】:

        猜你喜欢
        • 2018-05-23
        • 1970-01-01
        • 1970-01-01
        • 2021-03-30
        • 2017-09-24
        • 2010-09-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多