Как использовать мьютекс - PullRequest
       7

Как использовать мьютекс

2 голосов
/ 20 октября 2011

У меня есть один поток, который отправляет данные, хранящиеся в буфере типа List через tcp.Другой поток пишет в буфер.Поскольку я не очень знаком с 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()
    {
        //...
    }
}

Ответы [ 3 ]

4 голосов
/ 20 октября 2011

Было бы лучше, если вы используете 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;
        }
    }
}
2 голосов
/ 20 октября 2011

Следующий код не является потокобезопасным. Если два потока вводят этот метод одновременно, оба могут успешно пройти условие if.

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

Вы можете захотеть сделать что-то вроде этого:

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

Я не думаю, что вы делаете что-то сложное, что требует не только простого в использовании оператора блокировки.

1 голос
/ 20 октября 2011

Я бы не использовал мьютексы, поскольку полагаю, что вы не имеете дело с синхронизацией нескольких процессов.Блокировки довольно удобны и проще в реализации:

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();
...