Словарь, содержащий объекты для использования в операциях блокировки - PullRequest
0 голосов
/ 19 ноября 2018

В тех случаях, когда у меня есть не поточнобезопасный объект (такой как NetworkStream), к которому нужно обращаться из нескольких потоков, безопасно ли держать объект, который будет использоваться для блокировки, чтобы защитить не поточныйбезопасный объект, в значении ConcurrentDictionary (или обычный словарь)?

то есть, таким образом, у меня может быть несколько потоков, каждый из которых пытается записать данные в клиентский NetworkStream, но в каждый раз допускается только один поток?

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

Пример с использованием ConcurrentDictionary.Метод Send () будет вызываться несколькими потоками.Цель состоит в том, чтобы позволить нескольким вызывающим пользователям иметь доступ для записи в NetworkStream, и мне любопытно, может ли объект, найденный в значении ConcurrentDictionary, надежно использоваться в этом случае для блокировки.

// Assume this is prepopulated
private ConcurrentDictionary<string, object> locks = ...

public void Send(string identifier, byte[] data)
{
  object clientLock = null;
  if (locks.TryGetValue(identifier, out clientLock))
  {
    lock (clientLock)
    {
      // assume we have the TcpClient here
      NetworkStream ns = client.GetStream();
      ns.Write(data, 0, data.Length);
    }
  }
}

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

Только что протестировано и работает как положено.Спасибо всем за живой разговор.При запуске приведенного ниже примера кода Worker2 задерживается.

    static ConcurrentDictionary<string, object> locks = new ConcurrentDictionary<string, object>();

    static void Main(string[] args)
    {
        locks.TryAdd("foo", new object());
        Task.Run(() => Worker1());
        Task.Run(() => Worker2());
        Console.ReadKey();
    } 

    static void Worker1()
    {
        object lockObj = null;
        locks.TryGetValue("foo", out lockObj);
        lock (lockObj)
        {
            Console.WriteLine("Worker1");
            Thread.Sleep(10000);
        }
    }

    static void Worker2()
    {
        object lockObj = null;
        locks.TryGetValue("foo", out lockObj);
        lock (lockObj)
        {
            Console.WriteLine("Worker2"); 
        }
    }
0 голосов
/ 20 ноября 2018

В этом случае Словарь и мьютекс вообще могут быть ненужными. Обычно вы используете приватный объектный мьютекс, чтобы избежать тупиков. Таким образом, никакой другой код не может попытаться заблокировать это. Но в этом случае и объект-мьютекс, и материал, для которого он предназначен, де-факто public .

Если каждый поток способен выполнять блокировку / разблокировку как на ClientStreams, так и на объекте мьютекса, они не полностью выполняют свое предназначение. Вы можете просто заблокировать экземпляр ClientStream, что бы это ни было.

В качестве альтернативы создайте класс, структуру или tupel с объектами типов и ClientStream. Таким образом, у вас есть как Mutex, так и клиентский поток по крайней мере вместе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...